DEV Community

Subesh Yadav
Subesh Yadav

Posted on

🦀 Day 8 of #100DaysOfRust: Control Flow with match, if let, and let...else

Today, I explored some of the most expressive control flow constructs in Rust. These include match, if let, and let...else. These constructs allow pattern-based control handling with enums and other values — an area where Rust truly shines.

🎯 match – Rust’s Powerful Control Flow Tool

Rust's match is like a switch-case, but safer and more expressive. It lets you compare a value against multiple patterns and execute the corresponding code.

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,
    }
}
Enter fullscreen mode Exit fullscreen mode

Each match arm matches a value and executes associated logic. It's exhaustive by default, meaning every possible case must be handled — preventing bugs.

🧩 Patterns That Bind to Values

You can match against values and bind inner data:

enum Coin {
    Penny,
    Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
    match coin {
        Coin::Penny => 1,
        Coin::Quarter(state) => {
            println!("State quarter from {state:?}!");
            25
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This is useful for extracting values from enum variants and performing actions with them.

⚙️ Matching with Option

Option is Rust’s way of saying “something or nothing” — a safe alternative to null.

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

Rust ensures that you handle all cases, so it won't compile if you forget the None case.

✅ Exhaustive Matches

Rust’s compiler forces exhaustive matches. If you miss a case (like None in Option), the code won’t compile. This avoids many common runtime errors found in other languages.

🔁 Catch-All Patterns with _

When you want to ignore unmatched patterns, use _:

match dice_roll {
    3 => add_fancy_hat(),
    7 => remove_fancy_hat(),
    _ => (),
}
Enter fullscreen mode Exit fullscreen mode

Perfect for default actions or when you only care about a few specific patterns.

📦 Ownership and match

Be mindful: matching an enum with a non-copy type (like String) can move the value unless you borrow it:

let opt = Some(String::from("Hello"));
match &opt {
    Some(s) => println!("Found: {}", s),
    None => println!("Nothing!"),
}
Enter fullscreen mode Exit fullscreen mode

Matching on &opt lets you borrow and use the value without moving it.

✨ Cleaner Code with if let

When you only care about one pattern (like Some(T)), if let is concise:

if let Some(max) = config_max {
    println!("Max is {max}");
}
Enter fullscreen mode Exit fullscreen mode

This saves you from writing boilerplate match arms like _ => ().

🪛 Adding else to if let

Want to handle the unmatched case too? Use else:

if let Coin::Quarter(state) = coin {
    println!("State quarter: {state:?}");
} else {
    count += 1;
}
Enter fullscreen mode Exit fullscreen mode

🛣️ The “Happy Path” with let...else

let...else lets you focus on the success path, and return early otherwise:

let Coin::Quarter(state) = coin else {
    return None;
};

if state.existed_in(1900) {
    Some(format!("{state:?} is pretty old!"))
} else {
    Some(format!("{state:?} is new."))
}
Enter fullscreen mode Exit fullscreen mode

This keeps code flat and readable, avoiding nested conditionals.

🧠 Summary
Here’s what I’ve learned on Day 8:

  • match is powerful, exhaustive, and pattern-rich.
  • It binds values from enums like Option and Result.
  • if let and let...else are clean alternatives to match for simple or early-exit cases.
  • Catch-all patterns like _ simplify handling defaults.
  • Ownership matters in match — borrow if needed to avoid moves.

I now have a stronger grip on Rust’s control flow — it’s expressive, safe, and eliminates many common bugs by design!

Top comments (0)