Rust’s match expression is a powerful control flow construct that allows for pattern matching against values. It’s similar to switch statements in other languages but much more expressive, enabling destructuring, guards, and exhaustive checking.
Basic Syntax
The match expression evaluates an expression and compares its value against a series of patterns. Each pattern is followed by a => and a block of code to execute if the pattern matches.
let number = 5;
match number {
1 => println!("One"),
2 => println!("Two"),
3 => println!("Three"),
_ => println!("Something else"),
}
Patterns
Literals
Match against specific values:
let x = 1;
match x {
1 => println!("One"),
2 => println!("Two"),
3 => println!("Three"),
_ => println!("Other"),
}
Variables
Bind the matched value to a variable:
let x = 5;
match x {
n => println!("Got {}", n),
}
Wildcard
The _ pattern matches anything and ignores the value:
let x = Some(5);
match x {
Some(_) => println!("Got some value"),
None => println!("Got nothing"),
}
Multiple Patterns
Use | to match multiple patterns:
let x = 1;
match x {
1 | 2 | 3 => println!("Small number"),
4 | 5 | 6 => println!("Medium number"),
_ => println!("Large number"),
}
Matching on Enums
Enums are commonly used with match:
enum Color {
Red,
Green,
Blue,
}
let color = Color::Red;
match color {
Color::Red => println!("Red"),
Color::Green => println!("Green"),
Color::Blue => println!("Blue"),
}
For enums with data:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
let msg = Message::Move { x: 10, y: 20 };
match msg {
Message::Quit => println!("Quit"),
Message::Move { x, y } => println!("Move to ({}, {})", x, y),
Message::Write(text) => println!("Text: {}", text),
Message::ChangeColor(r, g, b) => println!("Color: ({}, {}, {})", r, g, b),
}
Matching on Structs
struct Point {
x: i32,
y: i32,
}
let point = Point { x: 10, y: 20 };
match point {
Point { x: 0, y: 0 } => println!("Origin"),
Point { x, y: 0 } => println!("On x-axis at {}", x),
Point { x: 0, y } => println!("On y-axis at {}", y),
Point { x, y } => println!("At ({}, {})", x, y),
}
Matching on Tuples
let tuple = (1, 2, 3);
match tuple {
(0, y, z) => println!("First is 0, y={}, z={}", y, z),
(1, ..) => println!("First is 1, rest ignored"),
_ => println!("Something else"),
}
Guards
Add conditions to patterns with if:
let num = Some(4);
match num {
Some(x) if x < 5 => println!("Less than five: {}", x),
Some(x) => println!("Five or more: {}", x),
None => println!("None"),
}
Exhaustiveness
Rust requires that match expressions be exhaustive - all possible values must be covered. The _ pattern is often used as a catch-all.
Binding with @
Use @ to bind a value while also testing it:
let msg = Message::Write(String::from("hello"));
match msg {
Message::Write(s @ String::from("hello")) => println!("Hello: {}", s),
Message::Write(s) => println!("Other: {}", s),
_ => (),
}
Match as Expression
match returns a value, so it can be used in assignments:
let result = match x {
1 => "one",
2 => "two",
_ => "other",
};
Advanced Patterns
References
let x = &Some(5);
match x {
&Some(n) => println!("Got {}", n),
&None => println!("None"),
}
Slices
let v = vec![1, 2, 3, 4, 5];
match v.as_slice() {
[first, second, ..] => println!("First: {}, Second: {}", first, second),
[single] => println!("Single: {}", single),
[] => println!("Empty"),
_ => println!("Many elements"),
}
Best Practices
- Use
matchfor exhaustive checking of enum variants. - Prefer
if letfor simple single-pattern matches. - Use guards sparingly to keep patterns readable.
- Leverage destructuring to extract data directly in patterns.
Conclusion
Rust’s match expression is a cornerstone of idiomatic Rust code, providing safe and expressive pattern matching. Mastering match allows you to write more robust and readable code, especially when working with enums and complex data structures.
For more advanced topics, explore the Rust documentation on pattern matching and consider using matches! macro for simple boolean checks.
Comments