C.W.K.
Stream
Lesson 03 of 06 · published

match — Exhaustive by Force

~12 min · enums, match, exhaustiveness

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

match is Rust's most powerful control-flow tool. It compares a value against patterns and runs the first arm that fits — but its superpower is that the compiler forces you to cover every case.

Match is an expression

Like if, match produces a value, so you can assign its result. Each arm is pattern => expression. The patterns can bind the data inside a variant: Some(n) => ... pulls the inner value out as n, ready to use in that arm.

Exhaustiveness is the magic

A match must handle every possible case, or it won't compile. Match on an Option and forget None? Compile error. This sounds pedantic until you change an enum: add a variant, and the compiler instantly lists every match that no longer covers all cases. Refactoring becomes a guided checklist instead of a hunt for forgotten spots.

Exhaustiveness turns 'I forgot a case' into a compile error. The bug that hides in a missing else or an unhandled enum value in other languages simply can't survive compilation here. Add a variant and the compiler hands you the to-do list.

The wildcard, used with care

_ matches anything and is how you say 'all remaining cases.' It's useful, but it also opts you out of exhaustiveness checking for future variants — add a new variant and a _ arm silently swallows it. Use _ when you truly mean 'everything else'; spell out variants when you want the compiler to remind you later.

Code

Exhaustive match, value-binding, and a guard·rust
enum Coin { Penny, Nickel, Dime, Quarter }

fn value(c: Coin) -> u32 {
    match c {                 // every variant MUST be covered
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}

fn main() {
    // match binds inner data and is an expression:
    let maybe = Some(7);
    let described = match maybe {
        Some(n) if n > 5 => format!("big: {n}"), // arm with a guard
        Some(n) => format!("small: {n}"),
        None => String::from("nothing"),
    };
    println!("{} {}", value(Coin::Dime), described);
}

External links

Exercise

Write an enum for the four cardinal directions and a match that maps each to a (dx, dy) movement tuple. Compile it. Now add a fifth variant (say Stay) to the enum but NOT to the match, and read the compiler error. What checklist did it just hand you?
Hint
The compiler reports the match is non-exhaustive and names the unhandled variant. That's exhaustiveness working for you: every match that needs updating is flagged the moment you add a variant.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.