21.16 Patterns in for Loops and Function Parameters

Patterns are also integral to other language constructs.

21.16.1 for Loops

for loops directly use irrefutable patterns to destructure the items yielded by an iterator.

fn main() {
    let coordinates = vec![(1, 2), (3, 4), (5, 6)];
    // `.iter()` yields `&(i32, i32)`. The pattern `(x, y)` destructures each tuple reference.
    // Note: `x` and `y` here will be references (`&i32`) due to iterating over references.
    // To get owned values, use `.into_iter()` on an owned collection.
    for &(x, y) in coordinates.iter() { // `&(x, y)` dereferences the item and destructures
        println!("Point: x={}, y={}", x, y); // x, y are i32 here
    }

    let map = std::collections::HashMap::from([("one", 1), ("two", 2)]);
    // Destructuring key-value pairs from HashMap iterator
    for (key, value) in map.iter() { // key is &&str, value is &i32
        println!("{}: {}", key, value);
    }
}

21.16.2 Function and Closure Parameters

Function and closure parameter lists are intrinsically patterns, allowing direct destructuring of arguments.

// Function destructuring a tuple argument
fn print_coordinates((x, y): (f64, f64)) {
    println!("Coordinates: ({:.2}, {:.2})", x, y);
}

// Function ignoring the first parameter
fn process_item(_index: usize, item_name: &str) {
    println!("Processing item: {}", item_name);
}

fn main() {
    print_coordinates((10.5, -3.2));

    process_item(0, "Apple"); // _index is ignored, no unused variable warning

    // Closure parameter destructuring
    let points = [(0, 0), (1, 5), (-2, 3)];
    points.iter().for_each(|&(x, y)| { // `|&(x, y)|` is the closure pattern
        println!("Closure saw point: ({}, {})", x, y);
    });
}