Start learning free

LESSON 85 OF 348 · CONDITIONAL STATEMENTS

Match Expressions in Rust in Rust

Lesson

You already know how to branch with if / else if chains. Rust has a second branching tool that is usually the better one: match. It looks like switch from other languages, but it is stronger in two ways. First, match is an expression — the whole thing evaluates to a value, so you can bind its result directly with let. Second, the arms are patterns, not just single values: an inclusive range like 90..=100 matches every number from 90 to 100.

let temp = 3;
let advice = match temp {
    30..=45 => "stay in the shade",
    10..=29 => "perfect day",
    _ => "bring a jacket",
};
println!("{}", advice);   // prints: bring a jacket

Each arm reads pattern => value, separated by commas. Whichever arm matches first, its value becomes the value of the whole match.


The trap:

The compiler checks that your arms cover every possible value. Match an i32 with only two ranges, and the build stops with this exact error:

error[E0004]: non-exhaustive patterns: `i32::MIN..=79_i32` and `101_i32..=i32::MAX` not covered
 --> src/main.rs:3:23
  |
3 |     let grade = match score {
  |                       ^^^^^ patterns `i32::MIN..=79_i32` and `101_i32..=i32::MAX` not covered
  |
  = note: the matched value is of type `i32`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard
      pattern, a match arm with multiple or-patterns as shown, or multiple match arms

The compiler is telling you which values fell through the cracks: everything below 80 and above 100. The fix is a catch-all arm, written _ => ..., which matches anything the earlier arms didn't. This exhaustiveness check is a feature: you can never silently forget a case.


Matching an Option:

match really shines on values that may be missing. nums.get(1) looks up index 1 of a vector safely: it returns Some(value) if the index exists and None if it doesn't (this two-case type is called an Option — no crashes, no null). A match handles both cases in one place:

let msg = match nums.get(1) {
    Some(v) => format!("found {}", v),
    None => String::from("nothing"),
};

Some(v) doesn't just match — it unpacks the inner value into v so the arm can use it. One rule to remember: all arms must produce the same type. format! builds an owned String, so the None arm answers with String::from("nothing") rather than a bare text literal.


Assignment
Follow the Coding Tutorial to grade a score with range patterns, then look up a vector element with a match on an Option:

  • Declare score as 87 and match it into grade: 90..=100 is an "A", 80..=89 is a "B", anything else (_) is a "C". Print the grade.
  • Build nums as vec![1, 2, 3] and match on nums.get(1): on Some(v) build format!("found {}", v), on None use String::from("nothing"). Print the message.

The exact expected output is:

grade = B
msg = found 2

Hint
If the compiler says non-exhaustive patterns, you're missing the _ catch-all arm. If it complains about mismatched types in the arms, make sure both Option arms produce a String.


STEP 1 OF 10
    Ctrl + Enter to check

    Match Expressions in Rust

    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free