🎓 A1Learner
🔍

Rust If Let

if let is the short form of a match that cares about one case. The block runs when the value fits the pattern.

The long way: a full match for one case

A whole match can test one case and ignore the rest:

let found: Option<i32> = Some(9);
match found {
    Some(n) => println!("found {n}"),
    None => println!("nothing found"),
}

One case is all you need

if let runs the block only when the value fits the pattern. Add an else block when the other case also needs code:

let found: Option<i32> = Some(9);
if let Some(n) = found {
    println!("found {n}");
} else {
    println!("nothing found");
}

while let loops until the pattern fails

pop() hands back an Option each round. while let keeps going while it is Some — and when None arrives, the loop ends by itself:

let mut words = vec!["a", "b"];
while let Some(w) = words.pop() {
    println!("word {w}");
}

if let tests shape, not equality

Door is a small enum with no derives. Comparing two Door values with == fails, because == needs PartialEq. if let asks only about shape, so it works either way:

let door = Door::Open;
if door == Door::Open {
    println!("open");
}
// error E0369: binary operation `==` cannot be applied to type `Door`

Join tests with && — let chains

On the 2024 edition, several let tests can join with &&, and a plain test can join them too. (On the 2021 edition the same code is an error.) The block runs only when every test passes:

let first = Some(3);
let second = Some(20);
if let Some(x) = first && let Some(y) = second && y > x {
    println!("both present, sum {}", x + y);
}

Example

fn main() {
    let mut stack = vec![1, 2, 3];
    while let Some(top) = stack.pop() {
        print!("{} ", top);
    }
    println!();
    let config: Option<&str> = Some("dark-mode");
    if let Some(mode) = config { println!("mode = {}", mode); }
}

Key points

  • Use let ... else to handle the "wrong" case early (usually by returning), keeping the main path flat
  • if let gives up a safety net.
  • Unlike match, it does not check that every case was handled.
  • That choice belongs to the programmer.
  • while let has no else.
  • When its pattern fails, the loop simply ends.
  • That ending is the whole point of the loop.

In this example, stack is a Vec holding 1, 2, 3. stack.pop() removes the last item and returns it as an Option: Some(3), then Some(2), then Some(1), then None. while let Some(top) = stack.pop() keeps the loop going while the pattern matches, printing 3 2 1. When pop finally returns None, the pattern fails and the loop ends by itself. Below, if let checks one Option once: it is Some("dark-mode"), so the mode line prints.

Note

if let is not a weaker match — it is the same pattern test, written briefly.

Reach for match when every case truly matters, like with Result.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

When is if let a better choice than match?