Syntax Cache
BlogMethodFeaturesHow It WorksBuild a Game
  1. Home
  2. Cheat Sheets
  3. Rust
  4. Rust Pattern Matching Cheat Sheet
RustCheat Sheet

Rust Pattern Matching Cheat Sheet

Quick-reference for every pattern matching construct in Rust. Each section includes copy-ready snippets with inline output comments.

On this page
  1. 1match Expressions
  2. 2Destructuring Structs
  3. 3Destructuring Enums & Tuples
  4. 4Matching Option and Result
  5. 5if let and let else
  6. 6while let
  7. 7Match Guards
  8. 8@ Bindings
  9. 9Multiple Patterns with |
  10. 10Slice Patterns
  11. 11Patterns Everywhere
match ExpressionsDestructuring StructsDestructuring Enums & TuplesMatching Option and Resultif let and let elsewhile letMatch Guards@ BindingsMultiple Patterns with |Slice PatternsPatterns Everywhere

match Expressions

match compares a value against patterns top-to-bottom and runs the first matching arm. It must be exhaustive.

Basic match on integers
let x = 3;
match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    _ => println!("other"),
}
// => "three"
match returns a value
let x = 5;
let label = match x {
    1..=3 => "small",
    4..=6 => "medium",
    _ => "large",
};
println!("{label}");  // => "medium"
match on enums
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.

Destructure in let binding
struct Point { x: i32, y: i32 }

let p = Point { x: 10, y: 20 };
let Point { x, y } = p;
println!("({x}, {y})");  // => "(10, 20)"
Rename fields in pattern
let Point { x: px, y: py } = p;
println!("({px}, {py})");
Ignore fields with ..
struct Rect { x: i32, y: i32, width: u32, height: u32 }

let Rect { width, height, .. } = rect;
println!("{width}x{height}");
Destructure in match
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 with tuple and struct variants
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})"),
}
Tuple destructuring
let (a, b, c) = (1, "hello", true);
println!("{a} {b} {c}");  // => "1 hello true"
Nested destructuring
let ((x, y), Point { x: px, .. }) = ((1, 2), point);
println!("{x} {y} {px}");
Ignore with _
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.

Match on Option
let opt: Option<i32> = Some(42);
match opt {
    Some(val) => println!("got {val}"),
    None => println!("nothing"),
}
Match on Result
let result: Result<i32, String> = Ok(10);
match result {
    Ok(n) => println!("success: {n}"),
    Err(e) => println!("error: {e}"),
}
Nested Option matching
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).

if let: handle one pattern
let config_max = Some(3u8);
if let Some(max) = config_max {
    println!("max is {max}");
}
if let with else
if let Some(val) = maybe_value {
    println!("got {val}");
} else {
    println!("nothing");
}
let else: bind or return early
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!.

Chained if let
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().

Pop from a stack
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
    println!("{top}");
}
// => 3, 2, 1
Iterate with next()
let 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.

Guard on a match arm
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"
Guard applies to entire | pattern
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.

Guard with variable binding
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.

@ with ranges
let age = 15;
match age {
    n @ 0..=12 => println!("child: {n}"),
    n @ 13..=19 => println!("teen: {n}"),
    n => println!("adult: {n}"),
}
// => "teen: 15"
@ with enum variants
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}"),
}
@ with slice patterns
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.

Literal alternatives
let x = 2;
match x {
    1 | 2 | 3 => println!("small"),
    _ => println!("big"),
}
// => "small"
| with enum variants
enum Dir { North, South, East, West }

match direction {
    Dir::North | Dir::South => println!("vertical"),
    Dir::East | Dir::West => println!("horizontal"),
}
All alternatives must bind same names
// 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 side

E0408: 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 by length
match slice {
    [] => println!("empty"),
    [one] => println!("single: {one}"),
    [a, b] => println!("pair: {a}, {b}"),
    _ => println!("three or more"),
}
First and last with ..
match slice {
    [first, .., last] => println!("first: {first}, last: {last}"),
    [only] => println!("single: {only}"),
    [] => println!("empty"),
}
Bind the rest with @ ..
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 binding
let (x, y, z) = (1, 2, 3);
println!("{x} {y} {z}");
Function parameters
fn print_point(&(x, y): &(i32, i32)) {
    println!("({x}, {y})");
}

print_point(&(3, 5));  // => "(3, 5)"
for loop destructuring
let pairs = vec![(1, 'a'), (2, 'b'), (3, 'c')];
for (num, letter) in &pairs {
    println!("{num}: {letter}");
}
Closure parameters
let sum = |(a, b): (i32, i32)| a + b;
println!("{}", sum((3, 4)));  // => 7
Learn Rust in Depth
Rust Structs & Enums Practice →Rust Error Handling Practice →
Warm-up1 / 2

Can you write this from memory?

Write a match expression on x that returns "one" for 1, "two" for 2, and "other" for anything else.

See Also
Enums →Error Handling →Iterators →

Start Practicing Rust

Free daily exercises with spaced repetition. No credit card required.

← Back to Rust Syntax Practice
Syntax Cache

Build syntax muscle memory with spaced repetition.

Product

  • Pricing
  • Our Method
  • Daily Practice
  • Design Patterns
  • Interview Prep

Resources

  • Blog
  • Compare
  • Cheat Sheets
  • Vibe Coding
  • Muscle Memory

Languages

  • Python
  • JavaScript
  • TypeScript
  • Rust
  • SQL
  • GDScript

Legal

  • Terms
  • Privacy
  • Contact

© 2026 Syntax Cache

Cancel anytime in 2 clicks. Keep access until the end of your billing period.

No refunds for partial billing periods.