পাঠ ৬.২

match Control Flow

The match Control Flow Construct

match Rust-এর সবচেয়ে শক্তিশালী control flow construct — একটা value-কে কয়েকটা pattern-এর সাথে compare করে, যেটা match হয় তার code চালায়। Coin-sorting machine-এর মতো — প্রতিটা coin নির্দিষ্ট ছিদ্রে গিয়ে পড়ে।

Basic match — Coin enum

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

প্রতিটা arm-এ দু'অংশ — pattern এবং =>-এর পরে কোড। উপর থেকে নিচে যেটা প্রথম match হয়, তার code চলে। match-এর result expression-এর value।

Multi-line arm

একটা arm-এ একাধিক line দরকার হলে curly bracket:

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => {
            println!("Lucky penny!");
            1
        }
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

Pattern-এ value bind করা

Variant-এ থাকা data extract করতে — pattern-এ variable binding:

#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    // --snip--
}

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter(state) => {
            println!("State quarter from {state:?}!");
            25
        }
    }
}

fn main() {
    value_in_cents(Coin::Quarter(UsState::Alaska));
}

Coin::Quarter(state) pattern match হলে, ভেতরের UsState state variable-এ bind হয়। তারপর arm-এর body-তে use করা যায়।

Option<T> match করা

plus_one — input Some(i) হলে এক বাড়ায়, None হলে None ফেরত:

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        None => None,
        Some(i) => Some(i + 1),
    }
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);

Some(5) Some(i)-এর সাথে match হলে i-এ 5 bind, then Some(6) return।

match exhaustive — সব case handle

Rust force করে — সব possible variant cover করতে হবে। নিচের code compile হবে না (None case missing):

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        Some(i) => Some(i + 1),
    }
}

এই exhaustiveness check Rust-এর সবচেয়ে boring কিন্তু সবচেয়ে দরকারি feature-গুলোর একটা। Null-pointer-style bug compile-time-এ ধরা পড়ে।

Catch-all এবং _ placeholder

সব case explicitly লিখতে হবে না — শেষে catch-all। Variable দিয়ে remaining value capture:

let dice_roll = 9;
match dice_roll {
    3 => add_fancy_hat(),
    7 => remove_fancy_hat(),
    other => move_player(other),
}

other-এ remaining value bind হয়। Value লাগবে না — শুধু match catch করতে চাই — তখন _:

let dice_roll = 9;
match dice_roll {
    3 => add_fancy_hat(),
    7 => remove_fancy_hat(),
    _ => reroll(),
}

কিছুই করতে চাও না — unit value ():

let dice_roll = 9;
match dice_roll {
    3 => add_fancy_hat(),
    7 => remove_fancy_hat(),
    _ => (),
}

লক্ষ্য করো — catch-all arm সবসময় শেষে। তার আগে রাখলে আগের arm-গুলো unreachable হয়ে যায়, compiler warning দেয়।

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

  • match — pattern + code, top-down, প্রথম match-এর code চলে।
  • Variant-এর data extract করতে pattern-এ binding (Coin::Quarter(state))।
  • Exhaustive — সব variant cover করতে হবে; না হলে compile error।
  • Catch-all variable-এ (other) বা _-এ; কিছু না করতে চাইলে => ()