Pattern Matching with match
match compares a value against patterns, binding variables and running the first matching arm. Compiler enforces exhaustiveness.
Recipe
enum Color { Red, Green, Blue }
fn label(c: Color) -> &'static str {
match c {
Color::Red => "red",
Color::Green => "green",
Color::Blue => "blue",
}
}When to reach for this: Enums, Option/Result, parsing tokens, and multi-way branching with destructuring.
Working Example
#[derive(Debug)]
enum Token { Num(i64), Ident(String), Eof }
fn eval(tok: Token) -> String {
match tok {
Token::Num(n) if n < 0 => format!("negative {n}"),
Token::Num(n) => n.to_string(),
Token::Ident(name) => name,
Token::Eof => "eof".into(),
}
}
fn main() {
println!("{}", eval(Token::Num(-3)));
}What this demonstrates:
- Binding
n,namefrom variant payloads - Guard
if n < 0refines match arm - Exhaustive arms for all variants
matchas expression returningString
Deep Dive
Pattern Forms
- Literals, ranges
1..=5 - Struct patterns
Point { x, y } - Tuple and slice patterns
@bindingsn @ 1..=100|or-patternsSome(0) | Some(1)
match vs if let
match handles many patterns; if let one pattern ergonomically.
Gotchas
- Missing variant after enum change - Compile error across crate. Fix: Update all matches (benefit of exhaustiveness).
- Binding mode in Rust 2024 -
mutbinding modes affect move/copy. Fix: Read edition migration guide forref/mutpatterns. - Non-exhaustive integers -
match x: u8needs_arm. Fix: Add wildcard or ranges. - Move in match arm - Binding moves unless
refpattern. Fix: Useref/ref mutto borrow fields. - Guard cannot borrow matched value oddly - Guard evaluated after pattern bind. Fix: Restructure guard or use
if letchain.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
if let / while let | Single pattern | Many variants |
matches! macro | Boolean test | Need bound values |
let-else | Early return on mismatch | Complex multi-arm logic |
if chain | Simple scalars | Enum with data |
FAQs
Must arms return same type?
Yes when `match` is an expression.Can I match references?
Yes: `match &opt { Some(v) => ..., None => ... }` with appropriate binds.What is `_`?
Wildcard ignoring value, must be last if used alone.Can patterns be refutable?
`if let` and `let-else` handle refutable patterns; `match` requires cover.Match on floats?
Allowed but no ordering ranges; use partial_eq or integer encoding.Deref in patterns?
Limited; often match on reference explicitly.Exhaustive lint for bool?
Not required - bool covered by true/false arms.Performance?
Compiled to jump tables/branches - zero-cost abstraction.Match guards order?
Arms tested top to bottom; first match wins.Nested match smell?
Flatten with combined patterns or helper functions.Related
- Enums - variants to match
- if let, let else & while let - partial match
- Destructuring - pattern forms
- Option & Result as Enums - core matches
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.