</>
Skip to content
Rust lessons (13/43)

Rust — Match

match is Rust's superpower

match compares a value against a series of patterns and runs the matching arm:

let coin = "heads";

match coin {
    "heads" => println!("You win"),
    "tails" => println!("You lose"),
    _       => println!("That's not a coin"),   // catch-all
}

Arrows (=>) separate patterns from code; commas separate arms.

Exhaustiveness — the killer feature

Every possibility MUST be covered or compilation fails:

match number {
    1 => println!("one"),
    2 => println!("two"),
    // ❌ error: non-exhaustive patterns — what about 0, 3, 4…?
}

Add _ (wildcard) to cover the rest. This guarantee means: add a new enum variant later, and the compiler lists every match you must update. Refactoring becomes mechanical safety.

match is an expression

let message = match code {
    200 => "OK",
    301 => "Moved",
    404 => "Not Found",
    _   => "Unknown",
};

All arms must produce the same type.

Matching ranges & multiple values

match age {
    0          => println!("newborn"),
    1..=12     => println!("child"),
    13..=19    => println!("teen"),
    n if n < 65 => println!("adult"),
    _          => println!("senior"),
}
  • 1..=12 — inclusive range
  • n if n < 65 — a guard: binds value to n, adds a condition

Destructuring — match by shape

let point = (3, -2);

match point {
    (0, 0)       => println!("origin"),
    (x, 0)       => println!("on x-axis at {}", x),
    (0, y)       => println!("on y-axis at {}", y),
    (x, y)       => println!("({}, {})", x, y),
}

Works on enums too — the pattern Rust was built around:

enum Shape {
    Circle(f64),                 // carries radius
    Rectangle { w: f64, h: f64 },// carries dimensions
}

fn area(shape: &Shape) -> f64 {
    match shape {
        Shape::Circle(r) => 3.14159 * r * r,
        Shape::Rectangle { w, h } => w * h,
    }
}

Option<T> — where match earns its keep

Rust has no null. Absence is expressed as an enum:

let maybe_name: Option<&str> = Some("Ada");

match maybe_name {
    Some(name) => println!("hello, {}", name),
    None       => println!("no name provided"),
}

The compiler forces you to handle the empty case — null-pointer errors are structurally impossible.

Gotchas: arms run in order — put specific patterns before _ · guards can't be used alone (n if … requires a binding) · match arms don't fall through like switch; no break needed.

Mini Practice

  1. Number-to-word translator for 0–5 with _ fallback.
  2. Grade bands using inclusive ranges + a guard for invalid (>100).
  3. Match a (x, y) tuple detecting all four quadrants.
  4. Define enum Status { Active, Banned(u32) }; write days_left() via match.
  5. Unwrap an Option<&str> greeting both cases manually.

Next: loops → (while/for next lessons)

Related Topics

Frequently Asked Questions about Match

What is Match in Rust?

Match is a fundamental concept in Rust. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Match?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Match.

Why is Match important in Rust?

Match is essential for Rust development. Understanding this concept will help you write better code and solve real-world problems more effectively.