Pattern Matching and Destructuring

Match Expression #

match compares a value against multiple patterns:

match value {
    pattern1 => expr1,
    pattern2 => expr2,
    _ => default_expr,
}

Pattern Types #

Literal Patterns #

Match exact values:

match x {
    0 => "zero",
    1 => "one",
    42 => "the answer",
    _ => "other",
}

Works with strings and booleans too:

match command {
    "quit" => exit(),
    "help" => show_help(),
    _ => print("unknown command"),
}

Variable Binding #

Bind the matched value to a name:

match x {
    n => print("got {n}"),
}

Wildcard _

Matches anything without binding:

match result {
    Result::Ok(value) => use(value),
    _ => {},  // ignore errors
}

Tuple Patterns #

Destructure tuples:

let point = (3, 4)

match point {
    (0, 0) => "origin",
    (x, 0) => "on x-axis at {x}",
    (0, y) => "on y-axis at {y}",
    (x, y) => "({x}, {y})",
}

Struct Patterns #

Destructure structs:

struct Point { x: f64, y: f64 }

match p {
    Point { x: 0.0, y: 0.0 } => "origin",
    Point { x, y } => "({x}, {y})",
}

Enum Patterns #

Destructure enum variants:

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
    Triangle { base: f64, height: f64 },
}

match shape {
    Shape::Circle(r) => 3.14 * r * r,
    Shape::Rectangle(w, h) => w * h,
    Shape::Triangle { base, height } => base * height / 2.0,
}

Or Patterns |

Match multiple patterns:

match key {
    'w' | 'W' | 'ArrowUp' => move_up(),
    's' | 'S' | 'ArrowDown' => move_down(),
    _ => {},
}

Guard Clauses if

Add conditions to patterns:

match value {
    n if n < 0 => "negative",
    0 => "zero",
    n if n > 100 => "large",
    n => "normal: {n}",
}

Nested Patterns #

Patterns can be nested arbitrarily:

match event {
    Event::Click { pos: Point { x, y }, button } if button == "left" => {
        handle_click(x, y)
    },
    Event::Key { code, modifiers: Mods { ctrl: true, .. } } => {
        handle_ctrl_key(code)
    },
    _ => {},
}

Destructuring in let

Tuple Destructuring #

let (x, y) = get_position()
let (first, ...rest) = items

Struct Destructuring #

let Point { x, y } = point
let Point { x: px, y: py } = point  // rename fields

For Loop Destructuring #

for (index, value) in list.enumerate() {
    print("{index}: {value}")
}

for (key, val) in map.entries() {
    print("{key} = {val}")
}

If Let #

Combine pattern matching with conditionals:

if let Some(value) = maybe_value {
    print("Got: {value}")
} else {
    print("Nothing")
}

With enums:

if let Shape::Circle(radius) = shape {
    print("Circle with radius {radius}")
}

Chained with else-if:

if let Result::Ok(data) = fetch_data() {
    process(data)
} else if let Result::Ok(cached) = read_cache() {
    process(cached)
} else {
    print("No data available")
}

While Let #

Loop while a pattern matches:

while let Some(item) = iterator.next() {
    process(item)
}

This is equivalent to:

loop {
    match iterator.next() {
        Some(item) => process(item),
        _ => break,
    }
}
enespt-br