Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The while let construct is a control flow operator that combines a while loop with pattern matching. It repeatedly evaluates an expression, attempts to bind the result to a specified pattern, and executes the loop body strictly as long as the pattern match succeeds. The loop terminates immediately upon the first matching failure.
fn main() {
    let mut iterator = vec![1, 2, 3].into_iter();
    
    // Loop body executes as long as `iterator.next()` matches the `Some(value)` pattern
    while let Some(value) = iterator.next() {
        println!("Matched: {}", value);
    }
}

Mechanics and Behavior

  • Evaluation: The expression on the right side of the = is evaluated at the beginning of every iteration.
  • Binding and Scope: If the evaluated expression matches the pattern on the left side of the =, any variables declared within the pattern are bound to the corresponding inner values. The scope of these bound variables is restricted entirely to the loop body.
  • Termination: If the expression evaluates to a variant that does not match the pattern (e.g., matching a Some(T) pattern against a None value), the binding fails, the loop terminates, and control flow proceeds to the statement immediately following the loop block.
  • Non-Exhaustiveness: Unlike a standard match expression, while let does not require exhaustive pattern matching. It implicitly handles all non-matching variants by breaking the loop, bypassing the need for a catch-all _ arm.

Desugared Equivalent

Internally, while let is syntactic sugar for an infinite loop containing a match expression that explicitly breaks on non-matching variants.
fn main() {
    let mut stream_one = vec![10].into_iter();
    
    // The while let construct:
    while let Some(value) = stream_one.next() {
        println!("while let: {}", value);
    }

    let mut stream_two = vec![20].into_iter();
    
    // Is structurally equivalent to:
    loop {
        match stream_two.next() {
            Some(value) => {
                println!("loop match: {}", value);
            }
            _ => break, // Implicit termination on match failure
        }
    }
}

Multiple Patterns

The while let construct supports matching against multiple patterns simultaneously using the pattern alternation operator (|), also known as an or-pattern. The loop continues as long as the expression matches any of the specified patterns. Any variables bound in the pattern must be bound in all alternatives.
enum Token {
    Integer(i32),
    Float(i32), // Using i32 for demonstration simplicity
    Eof,
}

fn main() {
    let mut tokens = vec![Token::Integer(1), Token::Float(2), Token::Eof, Token::Integer(3)];
    
    // Pops from the end: Integer(3), Eof, Float(2), Integer(1)
    // The loop terminates when it encounters Token::Eof
    while let Some(Token::Integer(val) | Token::Float(val)) = tokens.pop() {
        println!("Extracted numeric value: {}", val);
    }
}

Let Chains (Unstable / Nightly)

On nightly Rust toolchains, while let supports let chains via the unstable #![feature(let_chains)] flag. This feature allows combining multiple pattern matches and standard boolean conditions within a single while condition using the logical AND operator (&&). The loop body executes only if all chained conditions and pattern matches succeed sequentially. If any part of the chain fails, the evaluation short-circuits and the loop terminates. Variables bound in earlier let expressions within the chain are immediately in scope for subsequent conditions in the same chain, as well as within the loop body.
#![feature(let_chains)]

fn main() {
    let mut values = vec![1, 2, 3];
    let mut condition = true;

    // The loop requires:
    // 1. `values.pop()` to match `Some(val)`
    // 2. `condition` to evaluate to `true`
    // 3. `Some(val * 2)` to match `Some(doubled)`
    while let Some(val) = values.pop() && condition && let Some(doubled) = Some(val * 2) {
        println!("Processed: {}", doubled);
        
        if val == 2 {
            condition = false; // Will cause the chain to fail on the next iteration
        }
    }
}
Master Rust with Deep Grasping Methodology!Learn More