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

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

🔹 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)

🔹 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

🔹 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

🧠 Test Your Knowledge

What symbol represents the "catch-all" pattern in match expressions?