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
scoreas87and match it intograde:90..=100is an"A",80..=89is a"B", anything else (_) is a"C". Print the grade. - Build
numsasvec![1, 2, 3]and match onnums.get(1): onSome(v)buildformat!("found {}", v), onNoneuseString::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.
Free plan: 30 tutor messages. Premium is unlimited.