পাঠ ৫.২

Struct ব্যবহার করে একটি example program

An Example Program Using Structs

কখন struct use করা উচিত — সেটা একটা ছোট program-এর তিন stage refactor করে দেখব। কাজটা সহজ: rectangle-এর area বের করা।

Stage 1 — আলাদা variable

src/main.rsrust
fn main() {
    let width1 = 30;
    let height1 = 50;

    println!(
        "The area of the rectangle is {} square pixels.",
        area(width1, height1)
    );
}

fn area(width: u32, height: u32) -> u32 {
    width * height
}
terminal outputtext
The area of the rectangle is 1500 square pixels.

কাজ করছে। কিন্তু width1height1 — দুটো variable একসাথে সম্পর্কিত, এই কথা code-এ কোথাও বলা নেই। area-এ দুটো parameter আলাদা — আসলে এটা যে একটা rectangle, সেটা signature-এ বোঝা যাচ্ছে না।

Stage 2 — tuple দিয়ে refactor

src/main.rsrust
fn main() {
    let rect1 = (30, 50);

    println!(
        "The area of the rectangle is {} square pixels.",
        area(rect1)
    );
}

fn area(dimensions: (u32, u32)) -> u32 {
    dimensions.0 * dimensions.1
}

এক গ্রুপ-এ এসেছে — কিন্তু .0 width, না .1? Code পড়ে বোঝা যাচ্ছে না। Width-height পরে swap করে ফেললে bug ধরা যাবে না।

Stage 3 — struct দিয়ে refactor

src/main.rsrust
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!(
        "The area of the rectangle is {} square pixels.",
        area(&rect1)
    );
}

fn area(rectangle: &Rectangle) -> u32 {
    rectangle.width * rectangle.height
}

এখন signature বলছে — "একটা Rectangle-এর area বের কর"।

লক্ষ্য করো — area(&rect1)। ownership transfer না করে reference নিচ্ছি, যাতে main-এ rect1 পরে-ও ব্যবহার করা যায়।

Struct print করা

println!("rect1 is {rect1}"); চেষ্টা করলে error:

compile errortext
error[E0277]: `Rectangle` doesn't implement `std::fmt::Display`

{} placeholder Display trait দিয়ে print করে — যা primitive type-এ আছে কিন্তু custom struct-এ default-এ নেই (কারণ struct-এর field কীভাবে দেখাবে সেটা Rust জানে না)।

#[derive(Debug)] + {:?}

src/main.rsrust
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let rect1 = Rectangle {
        width: 30,
        height: 50,
    };

    println!("rect1 is {rect1:?}");
}
terminal outputtext
rect1 is Rectangle { width: 30, height: 50 }

#[derive(Debug)] attribute Rust-কে বলে "auto-generate Debug trait-এর implementation করে দাও"। তারপর {:?} placeholder এই debug format use করে।

Pretty-print — {:#?}

বড় struct-এ পড়ার সুবিধার জন্য multi-line:

println!("rect1 is {rect1:#?}");
terminal outputtext
rect1 is Rectangle {
    width: 30,
    height: 50,
}

dbg! macro

dbg! debugging-এর জন্য আরও powerful — file name, line number, expression text এবং value সব print করে। কিন্তু সাবধানে — এটা ownership নেয়, তারপর ফেরত দেয়। তাই reference না-পাঠালে variable move হয়ে যাবে।

src/main.rsrust
#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let scale = 2;
    let rect1 = Rectangle {
        width: dbg!(30 * scale),
        height: 50,
    };

    dbg!(&rect1);
}
terminal output (stderr)text
[src/main.rs:10:16] 30 * scale = 60
[src/main.rs:14:5] &rect1 = Rectangle {
    width: 60,
    height: 50,
}

dbg!(30 * scale) — value print করে এবং সেই value-ই return করে, তাই width-এ ৬০ বসে যাচ্ছে। dbg!(&rect1) — ownership না নিয়ে print করছি, তাই rect1 পরে-ও use করা যায়।

println! stdout-এ লেখে, dbg! stderr-এ — তাই প্রোগ্রামের মূল output-এর সাথে debug output mix হয় না।

এই পাঠ থেকে যা শিখলে

  • আলাদা variable → tuple → struct — code clarity-র progression।
  • Struct print করতে #[derive(Debug)] + {:?} বা {:#?} (pretty)।
  • dbg! — ownership নেয় (reference পাঠাও), stderr-এ print, file/line info দেয়।
  • derive attribute — auto-generated trait implementation।