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 {
39;w39; | 39;W39; | 39;ArrowUp39; => move_up(),
39;s39; | 39;S39; | 39;ArrowDown39; => 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,
}
}