Pattern Matching

Using the match expression and pattern matching.

Intermediate⏱️ 40 min📚 Prerequisites: 1

Pattern Matching

Pattern matching is one of Rust's most powerful features, allowing us to compare a value against different patterns.

Match Expression

RUST
match value {
    pattern1 => expression1,
    pattern2 => expression2,
    _ => default_case,
}

Exhaustive Matching

The match must be exhaustive - all possible cases must be covered:

RUST
match coin {
    Coin::Penny => 1,
    Coin::Nickel => 5,
    Coin::Dime => 10,
    Coin::Quarter => 25,
    // If we omitted one, we'd get an error!
}

Binding to Values

RUST
match value {
    Some(x) => println!("Value: {}", x),
    None => println!("No value"),
}

If Let

Simplified syntax for handling a single case:

RUST
if let Some(3) = some_option_value {
    println!("three");
}

While Let

RUST
while let Some(top) = stack.pop() {
    println!("{}", top);
}

Destructuring

RUST
let (x, y) = point;
let Point { x, y } = point;

Code Examples

Match Expression

Basic match usage

RUST
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,
    }
}
fn main() {
    let coin = Coin::Quarter;
    println!("Value: {} cents", value_in_cents(coin));
}

Explanation:

The match expression must cover all possible enum variants. The compiler checks that all cases are handled.

Binding to Values

Extracting data with pattern matching

RUST
enum Option<T> {
    Some(T),
    None,
}
fn main() {
    let some_number = Some(5);
    match some_number {
        Some(x) => println!("The value: {}", x),
        None => println!("No value"),
    }
    let absent_number: Option<i32> = None;
    match absent_number {
        Some(x) => println!("The value: {}", x),
        None => println!("No value"),
    }
}

Explanation:

Pattern matching allows us to directly bind data stored in enum variants to variables.

If Let

Using if let for simplified matching

RUST
fn main() {
    let some_value = Some(3);
    match some_value {
        Some(3) => println!("three"),
        _ => (),
    }
    if let Some(3) = some_value {
        println!("three");
    }
}

Explanation:

The `if let` is a shortened syntax when we only want to handle one case. It does the same as a single match arm, but more concisely.

Exercises

Match Practice

Write a function that handles an Option<i32> with match!

Medium

Starter Code:

RUST
fn handle_option(value: Option<i32>) {
}
fn main() {
    handle_option(Some(42));
    handle_option(None);
}