Rust Pattern Matching Cheat Sheet
Quick-reference for every pattern matching construct in Rust. Each section includes copy-ready snippets with inline output comments.
match Expressions
match compares a value against patterns top-to-bottom and runs the first matching arm. It must be exhaustive.
let x = 3;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("other"),
}
// => "three"let x = 5;
let label = match x {
1..=3 => "small",
4..=6 => "medium",
_ => "large",
};
println!("{label}"); // => "medium"enum Coin { Penny, Nickel, Dime, Quarter }
fn cents(coin: Coin) -> u32 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}The compiler enforces exhaustiveness. Forgetting a variant is a compile error (E0004).
Destructuring Structs
Pull fields out of structs directly in the pattern. Use .. to ignore remaining fields.
struct Point { x: i32, y: i32 }
let p = Point { x: 10, y: 20 };
let Point { x, y } = p;
println!("({x}, {y})"); // => "(10, 20)"let Point { x: px, y: py } = p;
println!("({px}, {py})");struct Rect { x: i32, y: i32, width: u32, height: u32 }
let Rect { width, height, .. } = rect;
println!("{width}x{height}");match point {
Point { x: 0, y } => println!("on y-axis at {y}"),
Point { x, y: 0 } => println!("on x-axis at {x}"),
Point { x, y } => println!("({x}, {y})"),
}Destructuring Enums & Tuples
Each enum variant can carry different data. Pattern matching is the only way to access it.
enum Message {
Quit,
Write(String),
Move { x: i32, y: i32 },
}
match msg {
Message::Quit => println!("quit"),
Message::Write(text) => println!("{text}"),
Message::Move { x, y } => println!("({x}, {y})"),
}let (a, b, c) = (1, "hello", true);
println!("{a} {b} {c}"); // => "1 hello true"let ((x, y), Point { x: px, .. }) = ((1, 2), point);
println!("{x} {y} {px}");let (first, _, third) = (1, 2, 3);
println!("{first} {third}"); // => "1 3"Matching Option and Result
Option<T> and Result<T, E> are just enums. Match on Some/None and Ok/Err.
let opt: Option<i32> = Some(42);
match opt {
Some(val) => println!("got {val}"),
None => println!("nothing"),
}let result: Result<i32, String> = Ok(10);
match result {
Ok(n) => println!("success: {n}"),
Err(e) => println!("error: {e}"),
}let nested: Option<Option<i32>> = Some(Some(5));
match nested {
Some(Some(n)) => println!("inner: {n}"),
Some(None) => println!("outer some, inner none"),
None => println!("nothing"),
}if let and let else
if let handles one pattern (ignores the rest). let else binds or diverges (return/break/panic).
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("max is {max}");
}if let Some(val) = maybe_value {
println!("got {val}");
} else {
println!("nothing");
}fn process(input: Option<&str>) -> String {
let Some(val) = input else {
return String::from("default"); // must diverge
};
val.to_uppercase()
}The else block must diverge: return, break, continue, or panic!.
if let Some(x) = opt_a {
println!("a: {x}");
} else if let Some(y) = opt_b {
println!("b: {y}");
} else {
println!("neither");
}while let
Loop while a pattern matches. Commonly used with iterators and stack.pop().
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("{top}");
}
// => 3, 2, 1let mut iter = [10, 20, 30].iter();
while let Some(&val) = iter.next() {
println!("{val}");
}Match Guards
Add conditions after a pattern with if. Guards do not count toward exhaustiveness.
let num = Some(4);
match num {
Some(x) if x < 5 => println!("less than five: {x}"),
Some(x) => println!("{x}"),
None => (),
}
// => "less than five: 4"let x = 4;
match x {
4 | 5 if true => println!("four or five"),
_ => println!("other"),
}
// Guard binds as (4 | 5) if condition, NOT 4 | (5 if condition)A guard applies to the entire | pattern, not just the last alternative.
match temperature {
t if t > 100 => println!("boiling: {t}"),
t if t < 0 => println!("freezing: {t}"),
t => println!("normal: {t}"),
}@ Bindings
Bind a name to a value while simultaneously testing it against a pattern.
let age = 15;
match age {
n @ 0..=12 => println!("child: {n}"),
n @ 13..=19 => println!("teen: {n}"),
n => println!("adult: {n}"),
}
// => "teen: 15"enum Msg { Hello { id: i32 } }
match msg {
Msg::Hello { id: id @ 3..=7 } => println!("id in range: {id}"),
Msg::Hello { id } => println!("other id: {id}"),
}let nums = [1, 2, 3, 4, 5];
match nums.as_slice() {
[head, tail @ ..] => {
println!("head: {head}, tail len: {}", tail.len());
}
[] => println!("empty"),
}
// => "head: 1, tail len: 4"Multiple Patterns with |
Match several patterns in one arm. Each alternative must bind the same variables.
let x = 2;
match x {
1 | 2 | 3 => println!("small"),
_ => println!("big"),
}
// => "small"enum Dir { North, South, East, West }
match direction {
Dir::North | Dir::South => println!("vertical"),
Dir::East | Dir::West => println!("horizontal"),
}// OK: both sides bind x
match pair {
(x, 0) | (0, x) => println!("{x}"),
(a, b) => println!("({a}, {b})"),
}
// ERROR: (x, 0) | (0, _) -- x not bound on right sideE0408: variable must be bound in all | alternatives.
Slice Patterns
Match on arrays and slices with [] syntax. Use .. for the rest (only once per pattern).
match slice {
[] => println!("empty"),
[one] => println!("single: {one}"),
[a, b] => println!("pair: {a}, {b}"),
_ => println!("three or more"),
}match slice {
[first, .., last] => println!("first: {first}, last: {last}"),
[only] => println!("single: {only}"),
[] => println!("empty"),
}match slice {
[head, tail @ ..] => {
println!("head: {head}, rest: {tail:?}");
}
[] => println!("empty"),
}Only one .. is allowed per pattern.
Patterns Everywhere
Patterns appear in let, for, function parameters, and closures -- not just match.
let (x, y, z) = (1, 2, 3);
println!("{x} {y} {z}");fn print_point(&(x, y): &(i32, i32)) {
println!("({x}, {y})");
}
print_point(&(3, 5)); // => "(3, 5)"let pairs = vec![(1, 'a'), (2, 'b'), (3, 'c')];
for (num, letter) in &pairs {
println!("{num}: {letter}");
}let sum = |(a, b): (i32, i32)| a + b;
println!("{}", sum((3, 4))); // => 7Can you write this from memory?
Write a match expression on x that returns "one" for 1, "two" for 2, and "other" for anything else.