Rust Pattern Matching
Powerful control flow with match expressions
🎯 What is Pattern Matching?
Pattern matching lets you compare values against patterns and execute code based on matches. It's like a powerful switch statement that ensures you handle all possible cases.
match number {
1 => println!("One"),
2 => println!("Two"),
_ => println!("Something else"),
}
Pattern Types
Literal Patterns
Match exact values
match x {
1 => "one",
2 => "two",
}
Destructuring
Extract values from structs/tuples
match point {
(0, 0) => "origin",
(x, 0) => "x-axis",
}
Guards
Additional conditions
match x {
n if n > 0 => "positive",
_ => "other",
}
Ranges
Match value ranges
match age {
0..=12 => "child",
13..=19 => "teen",
}
🔹 Basic Match Expressions
Use match to handle different values:
fn describe_number(n: i32) -> &'static str {
match n {
0 => "zero",
1 => "one",
2 => "two",
3..=10 => "small number",
11..=100 => "medium number",
_ => "large number",
}
}
fn main() {
let numbers = vec![0, 5, 15, 150];
for num in numbers {
println!("{} is {}", num, describe_number(num));
}
// Match with multiple patterns
let day = 3;
match day {
1 | 2 | 3 | 4 | 5 => println!("Weekday"),
6 | 7 => println!("Weekend"),
_ => println!("Invalid day"),
}
}
Output:
0 is zero
5 is small number
15 is medium number
150 is large number
Weekday
5 is small number
15 is medium number
150 is large number
Weekday
🔹 Destructuring Patterns
Extract values from complex data structures:
struct Point {
x: i32,
y: i32,
}
enum Shape {
Circle(f64),
Rectangle { width: f64, height: f64 },
Triangle(Point, Point, Point),
}
fn describe_shape(shape: Shape) {
match shape {
Shape::Circle(radius) => {
println!("Circle with radius {}", radius);
}
Shape::Rectangle { width, height } => {
println!("Rectangle {}x{}", width, height);
}
Shape::Triangle(p1, p2, p3) => {
println!("Triangle with points ({},{}), ({},{}), ({},{})",
p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
}
}
}
fn main() {
let shapes = vec![
Shape::Circle(5.0),
Shape::Rectangle { width: 10.0, height: 20.0 },
Shape::Triangle(
Point { x: 0, y: 0 },
Point { x: 3, y: 0 },
Point { x: 0, y: 4 }
),
];
for shape in shapes {
describe_shape(shape);
}
}
Output:
Circle with radius 5
Rectangle 10x20
Triangle with points (0,0), (3,0), (0,4)
Rectangle 10x20
Triangle with points (0,0), (3,0), (0,4)
🔹 Match Guards
Add extra conditions to patterns:
fn categorize_number(x: i32) -> &'static str {
match x {
n if n < 0 => "negative",
0 => "zero",
n if n % 2 == 0 => "positive even",
n if n % 2 == 1 => "positive odd",
_ => "impossible", // This will never match
}
}
fn analyze_tuple(pair: (i32, i32)) {
match pair {
(x, y) if x == y => println!("Equal: {} = {}", x, y),
(x, y) if x > y => println!("{} is greater than {}", x, y),
(x, y) if x < y => println!("{} is less than {}", x, y),
_ => println!("Impossible case"),
}
}
fn main() {
let numbers = vec![-5, 0, 4, 7];
for num in numbers {
println!("{} is {}", num, categorize_number(num));
}
let pairs = vec![(5, 5), (10, 3), (2, 8)];
for pair in pairs {
analyze_tuple(pair);
}
}
Output:
-5 is negative
0 is zero
4 is positive even
7 is positive odd
Equal: 5 = 5
10 is greater than 3
2 is less than 8
0 is zero
4 is positive even
7 is positive odd
Equal: 5 = 5
10 is greater than 3
2 is less than 8
🔹 if let and while let
Simplified pattern matching for single cases:
fn main() {
let some_option = Some(5);
let some_result: Result = Ok(10);
// if let - match one pattern
if let Some(value) = some_option {
println!("Got a value: {}", value);
} else {
println!("No value");
}
// if let with Result
if let Ok(value) = some_result {
println!("Success: {}", value);
}
// while let - loop while pattern matches
let mut stack = vec![1, 2, 3, 4, 5];
println!("Popping values:");
while let Some(value) = stack.pop() {
println!(" {}", value);
}
// Nested if let
let nested = Some(Some(42));
if let Some(inner) = nested {
if let Some(value) = inner {
println!("Nested value: {}", value);
}
}
}
Output:
Got a value: 5
Success: 10
Popping values:
5
4
3
2
1
Nested value: 42
Success: 10
Popping values:
5
4
3
2
1
Nested value: 42