21.13 if let and while let: Concise Conditional Matching

When you only care about matching one specific pattern and ignoring the rest, a full match can be verbose. if let and while let provide more concise alternatives.

21.13.1 if let

Handles a single refutable pattern. Executes the block if the pattern matches. Can optionally have an else block for the non-matching case.

fn main() {
    let config_value: Option<i32> = Some(5);

    // Using if let
    if let Some(value) = config_value {
        println!("Config value is: {}", value);
    } else {
        println!("Config value not set.");
    }

    let error_code: Result<u32, &str> = Err("Network Error");
    if let Ok(data) = error_code {
        // This block is skipped
        println!("Operation succeeded: {}", data);
    } else {
        println!("Operation failed."); // This block runs
    }
}

21.13.2 while let

Creates a loop that continues as long as the pattern matches the value produced in each iteration (commonly from an iterator or repeated function call).

fn main() {
    let mut tasks = vec![Some("Task 1"), None, Some("Task 2"), Some("Task 3")];

    // Process tasks from the end using pop() which returns Option<T>
    while let Some(task_option) = tasks.pop() { // Pattern: Some(task_option)
        if let Some(task_name) = task_option { // Nested Pattern: Some(task_name)
             println!("Processing: {}", task_name);
        } else {
             println!("Skipping empty task slot.");
        }
    }
     println!("Finished processing tasks.");
     // Example output order: Task 3, Task 2, Skipping empty task slot, Task 1

    // More direct with `while let Some(Some(..))` pattern:
    let mut data_stream = vec![Some(10), Some(20), None, Some(30)].into_iter();
    // The loop runs as long as `next()` returns `Some(Some(value))`
    while let Some(Some(value)) = data_stream.next() {
         println!("Received value: {}", value); // Outputs 10, 20, 30
    }
    println!("End of stream.");
}