7.2 Pattern Matching: match

Rust’s match construct is a significantly more powerful alternative to C’s switch statement. It allows you to compare a value against a series of patterns and execute code based on the first pattern that matches.

fn main() {
    let number = 2;
    match number {
        1 => println!("One"),
        2 => println!("Two"), // This arm matches
        3 => println!("Three"),
        _ => println!("Something else"), // Wildcard pattern, like C's `default`
    }
}

Key Features & Differences from C switch:

  1. Pattern-Based: match works with various patterns, not just simple integer constants like switch. Patterns can include literal values, variable bindings, ranges (1..=5), tuple destructuring, enum variants, and more (covered in Chapter 21).
  2. Exhaustiveness Checking: The Rust compiler requires match statements to be exhaustive. This means you must cover every possible value the matched expression could have. If you don’t, your code won’t compile. The wildcard pattern _ is often used as a catch-all, similar to default in C, to satisfy exhaustiveness.
  3. No Fall-Through: Unlike C’s switch, execution does not automatically fall through from one match arm to the next. Each arm is self-contained. You do not need (and cannot use) break statements to prevent fall-through between arms.
  4. match as an Expression: Like if, match is also an expression. Each arm must evaluate to a value of the same type if the match expression is used to produce a result.
fn main() {
    let number = 3;
    let result_str = match number {
        0 => "Zero",
        1 | 2 => "One or Two", // Multiple values with `|`
        3..=5 => "Three to Five", // Inclusive range
        _ => "Greater than Five",
    };
    println!("Result: {}", result_str); // Prints: Result: Three to Five
}

match is one of Rust’s most powerful features for control flow and data extraction, especially when working with enums like Option and Result.