Rust LogoAll the Places Patterns Can Be Used in Rust

Patterns are a powerful feature in Rust that allow you to destructure values, control program flow, and handle different data structures in a concise and expressive way. They are fundamental to Rust's type system and error handling. Here's a detailed look at the various contexts where patterns can be employed:

1. `let` Statements: Patterns are used on the left-hand side of `let` statements to bind values to names. This is commonly used for destructuring tuples, structs, and enums.
* Example: `let (x, y) = (1, 2);` or `let Point { x, y } = my_point;`

2. `match` Expressions: This is the most explicit and comprehensive use of patterns. `match` expressions allow you to compare a value against a series of patterns and execute code based on which pattern the value matches. `match` expressions must be *exhaustive*, meaning all possible values of the type must be covered by at least one pattern.
* Example: `match my_enum_value { SomeVariant(data) => ..., OtherVariant => ... }`

3. `if let` Expressions: `if let` is a convenient shorthand for a `match` expression that only cares about one specific pattern and ignores all other cases. It's often used for handling `Option<T>` or `Result<T, E>` values when you only care about the `Some` or `Ok` case.
* Example: `if let Some(value) = my_option { ... }`

4. `while let` Loops: Similar to `if let`, `while let` allows you to loop as long as a value matches a particular pattern. This is particularly useful for processing items from a collection or stream until a specific variant (like `None` or `Err`) is encountered.
* Example: `while let Some(item) = my_stack.pop() { ... }`

5. `for` Loops: Patterns can be used in `for` loops to destructure elements yielded by an iterator. This is very common when iterating over collections of tuples or structs.
* Example: `for (key, value) in my_map.iter() { ... }`

6. Function Parameters: You can use patterns directly in function signatures to destructure arguments as they are passed into the function. This can make function definitions cleaner and more readable.
* Example: `fn print_coords((x, y): (i32, i32)) { ... }`

7. Closure Parameters: Just like function parameters, patterns can be used in closure definitions to destructure arguments. This works identically to function parameters.
* Example: `let print_point = |Point { x, y }| { ... };`

In all these contexts, patterns provide a structured way to extract data from complex types, control flow based on the shape of data, and write more robust and readable Rust code.

Example Code

```rust
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}

struct Point {
    x: i32,
    y: i32,
}

// 6. Patterns in Function Parameters
fn process_point((x, y): (i32, i32)) { // Destructuring a tuple argument
    println!("Function: Processing point ({}, {})", x, y);
}

fn process_message_move(Message::Move { x, y }: Message) { // Destructuring an enum variant argument
    // Note: This function will panic if called with a non-Move message variant
    println!("Function: Direct move message processing: x={}, y={}", x, y);
}

fn main() {
    // 1. Patterns in `let` Statements
    let (a, b, c) = (1, 2, 3); // Destructuring a tuple
    println!("Let: a: {}, b: {}, c: {}", a, b, c);

    let p = Point { x: 10, y: 20 };
    let Point { x: p_x, y: p_y } = p; // Destructuring a struct (can rename fields)
    println!("Let: Struct point p_x: {}, p_y: {}", p_x, p_y);
    // Or simply `let Point { x, y } = p;` if field names are desired.

    // 2. Patterns in `match` Expressions
    let msg = Message::ChangeColor(255, 128, 64);
    match msg {
        Message::Quit => println!("Match: The Quit variant."),
        Message::Move { x: x_coord, y: y_coord } => { // Destructuring struct fields in enum
            println!("Match: Move to x: {}, y: {}", x_coord, y_coord);
        }
        Message::Write(text) => println!("Match: Text message: {}", text),
        Message::ChangeColor(r, g, b) => { // Destructuring tuple fields in enum
            println!("Match: Change color to R: {}, G: {}, B: {}", r, g, b);
        }
    }

    // 3. Patterns in `if let` Expressions
    let some_value = Some(3);
    if let Some(value) = some_value { // Matching `Some` variant of Option
        println!("If Let: Got a value from Some: {}", value);
    } else {
        println!("If Let: Got Nothing.");
    }

    let msg2 = Message::Move { x: 5, y: 10 };
    if let Message::Move { x: move_x, y: move_y } = msg2 { // Matching an enum variant
        println!("If Let: Accessed move message with if let: x={}, y={}", move_x, move_y);
    }

    // 4. Patterns in `while let` Loops
    let mut stack = vec![1, 2, 3];
    while let Some(top) = stack.pop() { // Looping as long as `pop()` returns `Some`
        println!("While Let: Popped {} from stack.", top);
    }

    // 5. Patterns in `for` Loops
    let pairs = vec![(1, 'a'), (2, 'b'), (3, 'c')];
    for (num, char_val) in pairs { // Destructuring a tuple in a for loop
        println!("For Loop: Number: {}, Character: {}", num, char_val);
    }

    let messages_list = vec![
        Message::Write(String::from("Hello")),
        Message::Move { x: 1, y: 2 },
        Message::Quit,
    ];
    for msg_item in messages_list {
        if let Message::Write(text) = msg_item { // Nested if let within for loop is common
            println!("For Loop + If Let: Found a write message: {}", text);
        }
    }

    // 6. Patterns in Function Parameters (already defined above)
    process_point((100, 200));
    // process_message_move(Message::Quit); // This would panic!
    process_message_move(Message::Move { x: 77, y: 88 });

    // 7. Patterns in Closure Parameters
    let print_coords = |Point { x, y }| { // Destructuring a struct argument in a closure
        println!("Closure: Received x: {}, y: {}", x, y);
    };
    print_coords(Point { x: 30, y: 40 });

    let sum_tuple_elements = |(val1, val2): (i32, i32)| {
        println!("Closure: Sum of tuple elements: {}", val1 + val2);
    };
    sum_tuple_elements((5, 7));
}
```