পাঠ ৮.১

Vector দিয়ে list রাখা

Storing Lists of Values with Vectors

Vec<T> Rust-এর growable list — একই type-এর একাধিক value contiguous memory-তে রাখে। array-এর মতো — কিন্তু size dynamic, heap-এ থাকে।

নতুন Vector তৈরি

খালি vector — type annotate করতে হয়:

fn main() {
    let v: Vec<i32> = Vec::new();
}

কোনো initial value না দেওয়ায় Rust infer করতে পারছে না — তাই : Vec<i32>

সাধারণত আমরা vec! macro use করি — initial value-গুলো দিলে type infer হয়:

fn main() {
    let v = vec![1, 2, 3];
}

Update — push

fn main() {
    let mut v = Vec::new();

    v.push(5);
    v.push(6);
    v.push(7);
    v.push(8);
}

mut দরকার (modify হচ্ছে)। Type compiler push-এর value দেখে infer করছে।

Element read করার দু'উপায়

১. Index access — out-of-bounds হলে panic:

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let third: &i32 = &v[2];
    println!("The third element is {third}");
}

২. .get() — out-of-bounds হলে None return, panic না:

fn main() {
    let v = vec![1, 2, 3, 4, 5];

    let third: Option<&i32> = v.get(2);
    match third {
        Some(third) => println!("The third element is {third}"),
        None => println!("There is no third element."),
    }
}

কখন কোনটা?[] — যখন invalid access হলে program crash চাও (bug সাথে সাথে ধরা পড়ুক)। .get() — যখন graceful handle করতে চাও।

Borrow-checker — reference vs push

এই code compile হবে না:

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let first = &v[0];

    v.push(6);

    println!("The first element is: {first}");
}
compile errortext
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable

কেন? — vector full হয়ে গেলে push reallocate করে data নতুন memory-তে copy করে। তখন আগের first reference invalid হয়ে যেত। Rust এই dangling pointer compile-time-এই block করে।

Iterate করা

Immutable iterate:

fn main() {
    let v = vec![100, 32, 57];
    for i in &v {
        println!("{i}");
    }
}

Mutable iterate — element-গুলো বদলাতে:

fn main() {
    let mut v = vec![100, 32, 57];
    for i in &mut v {
        *i += 50;
    }
}

*idereferencei reference, *i মূল value। * operator-এর বিস্তারিত Chapter 15-এ।

Iterate-এর সময় insert/remove allowed না — borrow-checker prevent করে।

একাধিক type — enum দিয়ে trick

Vec-এ সব same type। কিন্তু compile-time-এ জানা variant-গুলোর combination চাইলে enum:

enum SpreadsheetCell {
    Int(i32),
    Float(f64),
    Text(String),
}

let row = vec![
    SpreadsheetCell::Int(3),
    SpreadsheetCell::Text(String::from("blue")),
    SpreadsheetCell::Float(10.12),
];

সব element SpreadsheetCell type-এর — Rust satisfied। যখন iterate বা access করব, তখন match দিয়ে variant-অনুযায়ী handle করতে হবে।

Compile-time-এ variant জানা না থাকলে — trait object (Chapter 18-এ)।

Vector drop = element-ও drop

fn main() {
    {
        let v = vec![1, 2, 3, 4];

        // do stuff with v
    } // <- v goes out of scope and is freed here
}

Vec drop হলে এর সব element-ও drop হয়। Borrow-checker নিশ্চিত করে — vec valid থাকা পর্যন্তই তার element-এর reference valid।

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

  • Vec::new() বা vec![1,2,3]; .push() দিয়ে add (mut)।
  • Read — &v[i] (panic) বা v.get(i) (Option)।
  • Reference + push একসাথে allowed না — reallocation invalidate করে।
  • for i in &v, for i in &mut v (with *i dereference)।
  • একাধিক type চাইলে enum variant; compile-time-এ unknown হলে trait object (পরে আসবে)।