Let Control Flow

Rust has a few control flow constructs which differ from other languages. They are used for pattern matching:

  • if let expressions
  • while let expressions
  • match expressions

if-let expressions

The if let expression lets you execute different code depending on whether a value matches a pattern:

use std::{time::Duration, thread::sleep};

fn sleep_for(secs: f32) {
    let dur = if let Ok(dur) = Duration::try_from_secs_f32(secs) {
        dur
    } else {
        Duration::from_millis(500)
    };
    sleep(dur);
    println!("slept for {:?}", dur);
}

fn main() {
    sleep_for(-10.0);
    sleep_for(0.8);
}

let-else

For the common case of matching a pattern and returning from the function, use let else. The “else” case must diverge (return, break, or panic - anything but falling off the end of the block).

use std::{time::Duration, thread::sleep};

fn sleep_for(secs: f32) {
    let Ok(dur) = Duration::try_from_secs_f32(secs) else {
        println!("Invalid seconds value!");
        return;
    };
    sleep(dur);
    println!("slept for {:?}", dur);
}

fn main() {
    sleep_for(-10.0);
    sleep_for(0.8);
}

while-let

Like with if let, there is a while let variant which repeatedly tests a value against a pattern:

fn main() {
    let mut name = String::from("Comprehensive Rust 🦀");
    while let Some(c) = name.pop() {
        println!("character: {c}");
    }
    // (There are more efficient ways to reverse a string!)
}

Here String::pop returns Some(c) until the string is empty, after which it will return None. The while let lets us keep iterating through all items.

This slide should take about 10 minutes.

if-let

  • Unlike match, if let does not have to cover all branches. This can make it more concise than match.
  • A common usage is handling Some values when working with Option.
  • Unlike match, if let does not support guard clauses for pattern matching.

let-else

if-lets can pile up. The let-else construct supports flattening nested code.

while-let

  • Point out that the while let loop will keep going as long as the value matches the pattern.
  • You could rewrite the while let loop as an infinite loop with an if statement that breaks when there is no value to unwrap for name.pop(). The while let provides syntactic sugar for the above scenario.