if let in Rust: while let, let-else & match Guide

Max WellsMax WellsFounder of Rustify

TL;DR: if let Some(x) = optional { use(x) } is shorthand for a match with one useful arm and a fallback. It extracts values from Option, Result, or any enum variant without the noise of a full match. Use if let when you only care about one pattern. Use match when you need to handle all variants. The related while let loops until a pattern stops matching. let-else (Rust 1.65+) is the inverse: unwrap or return early.


What Is if let?

if let matches a single pattern and executes the body if it matches; ignoring all other variants.

// Without if let; verbose match
let config = get_config();
match config {
    Some(cfg) => println!("host: {}", cfg.host),
    None => {}  // nothing to do for None
}
 
// With if let; cleaner
if let Some(cfg) = get_config() {
    println!("host: {}", cfg.host);
}

It also works with Result:

if let Ok(data) = std::fs::read_to_string("config.toml") {
    println!("loaded {} bytes", data.len());
}
 
if let Err(e) = validate_input(&input) {
    eprintln!("validation failed: {e}");
    return;
}

How Do You Add an else Branch?

if let supports an else clause for the non-matching case.

if let Some(user) = find_user(id) {
    println!("found: {}", user.name);
} else {
    println!("user not found");
}
 
// Equivalent match:
match find_user(id) {
    Some(user) => println!("found: {}", user.name),
    None => println!("user not found"),
}

How Do You Match Nested or Complex Patterns?

if let supports the same patterns as match; destructuring, guards, and nested enums.

#[derive(Debug)]
enum Response {
    Success { code: u16, body: String },
    Error { code: u16, message: String },
    Timeout,
}
 
let response = get_response();
 
// Destructure a struct variant
if let Response::Success { code, body } if code == 200 = response {
    println!("OK: {body}");
}
 
// Nested Option
if let Some(Some(inner)) = nested_option {
    println!("deep value: {inner}");
}
 
// Tuple
if let (Some(x), Some(y)) = (opt_x, opt_y) {
    println!("both present: {x}, {y}");
}

What Is while let?

while let loops as long as a pattern keeps matching; commonly used to drain iterators, channels, or stacks.

use tokio::sync::mpsc;
 
let (tx, mut rx) = mpsc::channel::<String>(32);
 
// Process messages until channel is closed
while let Some(message) = rx.recv().await {
    println!("received: {message}");
}
 
// Pop from a stack until empty
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
    println!("popped: {top}");
}

What Is let-else (the Inverse)?

let-else (Rust 1.65+) unwraps a pattern or runs a diverging block; the idiomatic way to return/break early on mismatch.

// if let; happy path inside the block
if let Some(user) = find_user(id) {
    // ... 5 levels of indentation later
}
 
// let-else; happy path continues at same level
let Some(user) = find_user(id) else {
    return Err("user not found");
};
// user is available here, unindented
println!("user: {}", user.name);

let-else requires the else block to diverge (return, break, continue, panic!): it can't fall through.


When to Use if let vs match?

SituationUse
Only one pattern mattersif let
Need to handle all variantsmatch
Want an else branch tooif let ... else or match
Unwrap or return earlylet-else
Loop until pattern failswhile let
Multiple patterns with |match

Frequently Asked Questions

Yes, with | in the pattern:

if let Status::Active | Status::Pending = user.status {
    process(&user);
}

Yes; if let is an expression and works anywhere an expression is valid, including closures and iterator adapters.

.map() transforms a value inside Option or Result without leaving the monad. if let extracts the value for use in imperative code. Use .map() for functional chains; use if let when you need side effects or early returns.

No. if let is a language construct, not a method. There's no .if_let() method. Some codebases use .map(|v| { ... }) or .is_some_and(|v| ...) for similar patterns.


Sources


  • Pattern Matching: if let is a shorthand pattern match
  • Option: The most common target for if let
  • Result: if let Ok(v) / if let Err(e) patterns
  • Enum: if let works on any enum variant

Keep Reading

Ready to Land a $120k+ Rust Job in the US or Europe?