← Back to Rust series
🦀
Type system
Type system · Prerequisite: lesson 12

13. Pattern Matching (match · if let · while let)

Rust's pattern matching is a different beast from switch in other languages — it does value matching plus destructuring plus guards plus ref/mut binding in one form. This lesson covers match arm patterns, guards, ranges, OR patterns, and the shorter `if let` / `while let`.

Rustmatchpatternif letwhile letguard
Duration
~1.5 hours
Level
📊 Intermediate
Prerequisite
🎯 Lesson 12
OUTCOME
Rust's pattern matching is a different beast from switch in other languages — it does value matching plus destructuring plus guards plus ref/mut binding in one form. This lesson covers match arm patterns, guards, ranges, OR patterns, and the shorter `if let` / `while let`.

What you'll learn

  • 1Distinguish literal / variable / wildcard / range / OR patterns
  • 2Destructure tuples / structs / enums via patterns
  • 3Add `if` guards to match arms
  • 4Use `if let` for single-variant short forms
  • 5Use `while let` to iterate while an iterator yields Some

Overview

Pattern matching keeps Rust code short and safe. Splitting a value into cases inside a single expression cuts temporary variables and clarifies intent at a glance.

Core Concepts

1) Basic match arm patterns

PatternExampleMeaning
literal1, "hi"exact value
variablexbind any value to x
wildcard_any value, no binding
range1..=51 through 5
OR1 | 2 | 3one of these
destructurePoint { x, y }extract fields

2) match is an expression with exhaustive checking

It produces a value, and missing a variant is a **non-exhaustive patterns** compile error. You'll get used to that diagnostic.

3) Guards — if on a match arm

rust
match n {
    x if x < 0 => println!("negative"),
    0         => println!("zero"),
    x         => println!("positive {}", x),
}

4) if let / while let — single-variant focus

Syntactic sugar for the case where only one variant matters.

Hands-on Examples

Tuple / enum destructuring with guards:

rust
fn classify(p: (i32, i32)) -> &'static str {
    match p {
        (0, 0)               => "origin",
        (x, 0) if x > 0      => "positive x-axis",
        (x, 0)               => "negative x-axis",
        (0, y) if y > 0      => "positive y-axis",
        (0, _)               => "negative y-axis",
        (x, y) if x == y     => "on y=x",
        _                    => "other",
    }
}

fn main() {
    for p in [(0,0),(3,0),(0,-2),(5,5),(2,7)] {
        println!("{:?} → {}", p, classify(p));
    }
}

if let — single variant of interest:

rust
let some_val: Option<i32> = Some(7);
if let Some(n) = some_val {
    println!("got {}", n);
} else {
    println!("none");
}

while let — iterate while Some:

rust
fn main() {
    let mut stack = vec![1, 2, 3, 4];
    while let Some(top) = stack.pop() {
        println!("{}", top); // 4, 3, 2, 1
    }
}

@ binding — check value while capturing:

rust
let n = 42;
match n {
    x @ 1..=50 => println!("in 1~50: {}", x),
    _          => println!("out of range"),
}

Common Mistakes

Q. What's the difference between `_` and a variable name?

A. `_` ignores the value (no binding). A variable name **captures** the value, so you can use it in a guard or the body.

Q. Too many variants — can I just use `_`?

A. You can, but you lose the safety net of having the compiler tell you when a new variant is added. Prefer explicit patterns when feasible.

Q. Does `if let` have an `else`?

A. Yes — `if let Some(x) = opt { ... } else { ... }`. There's also `let-else` for unwrapping into the surrounding flow.

Recap

  • match is an expression, exhaustive over variants
  • Patterns: literal / variable / wildcard / range / OR / destructure / @-binding
  • Guards add `if` conditions to arms
  • Use if let / while let / let-else for concise single-case handling

Try It Yourself

  1. Define `enum Direction { Up, Down, Left, Right }` and return (dx, dy) tuples via match
  2. Take Vec<Option<i32>> and extract only Some values into a Vec<i32>
  3. Use @-binding to bucket numbers into 1~9 / 10~99 / 100+ while keeping the original value
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗