Pattern Usage Contexts

match Arms

match VALUE {
    PATTERN => EXPRESSION,
    PATTERN => EXPRESSION,
}

match expressions must be exhaustive. Use _ as a catchall pattern:

match x {
    None => None,
    Some(i) => Some(i + 1),
}

Conditional if let Expressions

More flexible than match for single-pattern matching:

fn main() {
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age: Result<u8, _> = "34".parse();

    if let Some(color) = favorite_color {
        println!("Using your favorite color, {color}, as the background");
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
}

if let doesn’t check exhaustiveness, unlike match. Can introduce shadowed variables within the conditional scope.

while let Conditional Loops

fn main() {
    let (tx, rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        for val in [1, 2, 3] {
            tx.send(val).unwrap();
        }
    });

    while let Ok(value) = rx.recv() {
        println!("{value}");
    }
}

Continues until the pattern fails to match.

for Loops

The pattern follows for:

fn main() {
    let v = vec!['a', 'b', 'c'];

    for (index, value) in v.iter().enumerate() {
        println!("{value} is at index {index}");
    }
}

Output:

$ cargo run
   Compiling patterns v0.1.0 (file:///projects/patterns)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
     Running `target/debug/patterns`
a is at index 0
b is at index 1
c is at index 2

let Statements

Every let statement uses a pattern:

let x = 5;  // x is a pattern

Formal syntax: let PATTERN = EXPRESSION;

Destructuring example:

fn main() {
    let (x, y, z) = (1, 2, 3);
}

Pattern elements must match exactly:

fn main() {
    let (x, y) = (1, 2, 3);
}

Error:

$ cargo run
   Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0308]: mismatched types
 --> src/main.rs:2:9
  |
2 |     let (x, y) = (1, 2, 3);
  |         ^^^^^^   --------- this expression has type `({integer}, {integer}, {integer})`
  |         |
  |         expected a tuple with 3 elements, found one with 2 elements
  |
  = note: expected tuple `({integer}, {integer}, {integer})`
             found tuple `(_, _)`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error

Function Parameters

Function parameters are patterns:

fn foo(x: i32) {
    // code goes here
}

fn main() {}

Destructuring in function signatures:

fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({x}, {y})");
}

fn main() {
    let point = (3, 5);
    print_coordinates(&point);
}

Prints: Current location: (3, 5)

Closure parameters work the same way as function parameters.