What is pattern matching in Rust and how does the match expression work?
Learn how pattern matching and the match expression work in Rust, including exhaustiveness, destructuring, guards and the wildcard, with clear code examples.
Expected Interview Answer
Pattern matching in Rust is a control-flow feature that compares a value against a series of patterns and runs the code for the first pattern that fits; the match expression is its primary form and must cover every possible case exhaustively.
A match expression takes a value and a list of arms, each an pattern plus code. The compiler checks that the arms are exhaustive, so an enum like Option or Result forces you to handle every variant or add a catch-all _ arm. Patterns can destructure structs, tuples, and enums, bind inner values to names, match ranges, and add guard conditions with if. Because match is an expression, every arm returns a value and the whole match evaluates to one.
- Compiler-enforced exhaustiveness catches unhandled cases at compile time
- Destructures nested data and binds inner values in one step
- Replaces long if/else chains with clear, readable branches
- Works as an expression, so it can return values directly
- Guards and ranges express complex conditions concisely
AI Mentor Explanation
Think of a third umpire reviewing a dismissal appeal: they run through a fixed checklist of outcomes, caught, bowled, LBW, run-out, not-out, and stop at the first that matches the replay. Rust's match is that checklist, and exhaustiveness means the umpire must have a verdict for every possible appeal, never leaving a decision undefined.
Step-by-Step Explanation
Step 1
Provide a value
Give match a value to inspect, commonly an enum such as Option<T> or Result<T, E>.
Step 2
List the arms
Write pattern => expression arms, one per case you want to handle.
Step 3
Destructure and bind
Use patterns to pull inner values out and bind them to names, e.g. Some(x) or Point { x, y }.
Step 4
Add guards if needed
Attach an if condition to an arm to refine when it matches beyond structure.
Step 5
Ensure exhaustiveness
Cover every variant or add a final _ catch-all arm so the compiler accepts the match.
What Interviewer Expects
- Knows match must be exhaustive and why the compiler enforces it
- Can destructure enums, structs and tuples inside patterns
- Understands match is an expression that returns a value
- Knows about guards, ranges and the _ wildcard
- Can contrast match with if let for single-case handling
Common Mistakes
- Forgetting a variant and only realizing when the compiler errors
- Overusing _ catch-all and hiding genuinely unhandled cases
- Thinking match falls through like a C switch statement
- Not binding inner values and re-accessing them awkwardly
- Using a full match where a concise if let would read better
Best Answer (HR Friendly)
“Pattern matching lets Rust look at a value and pick the right branch of code based on its shape, a bit like a checklist that handles each possibility. The match keyword is the main way to do it, and Rust insists you cover every case so nothing is accidentally left unhandled.”
Code Example
enum Shape {
Circle(f64),
Rectangle(f64, f64),
}
fn area(shape: Shape) -> f64 {
match shape {
Shape::Circle(r) => std::f64::consts::PI * r * r,
Shape::Rectangle(w, h) if w == h => w * w,
Shape::Rectangle(w, h) => w * h,
}
}
fn describe(n: Option<i32>) -> &'static str {
match n {
Some(x) if x > 0 => "positive",
Some(0) => "zero",
Some(_) => "negative",
None => "nothing",
}
}Follow-up Questions
- How does if let differ from a full match expression?
- What is the purpose of the _ wildcard pattern?
- How do match guards work and when are they useful?
- Can you match on ranges of values, and how?
- What are binding modes and the @ operator in patterns?
MCQ Practice
1. What does the Rust compiler require of every match expression?
Rust requires match to be exhaustive: every possible value must be covered by some arm, or a _ catch-all must be present.
2. What does the pattern Some(x) do in a match arm?
Some(x) matches the Some variant of an Option and binds the contained value to the name x for use in that arm.
3. How does Rust's match differ from a C-style switch?
Rust match arms do not fall through and match is an expression, so the matched arm's value becomes the value of the whole match.
Flash Cards
Is match an expression or a statement? — An expression, it evaluates to a value, so every arm must produce a compatible type.
What does exhaustiveness mean for match? — Every possible value must be handled by an arm, or a _ wildcard must cover the rest.
What is a match guard? — An extra if condition on an arm that further restricts when that arm matches.
When prefer if let over match? — When you only care about one pattern and want to ignore the rest without writing a full match.