We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Errors Are Values step 2 of 24
Matching on Option
Complete two functions using pattern matching:
pub fn classify(items: Vec<Option<i32>>) -> Vec<String>
pub fn first_pair(a: Option<i32>, b: Option<i32>) -> Option<i32>
Classify every input
Return one label per input, preserving order and duplicates:
| Input | Label |
|---|---|
None |
"none" |
Some(0) |
"zero" |
Some(n) with n < 0 |
"neg:{n}", including the minus sign |
Some(n) with n > 0 |
"pos:{n}" |
For example, [Some(1), Some(-2), Some(0), None] becomes
["pos:1", "neg:-2", "zero", "none"]. Empty input returns an empty vector.
Format the integer directly; no absolute-value calculation is needed, even
for i32::MIN.
Keep the first value when both are present
first_pair returns the integer from a only when both inputs are Some:
a |
b |
Result |
|---|---|---|
Some(2) |
Some(9) |
Some(2) |
Some(2) |
None |
None |
None |
Some(9) |
None |
None |
None |
None |
Some(0) |
Some(0) |
Some(0) |
Zero and negative integers are present values. The integer inside b does
not affect the result; only its presence matters. Match (a, b) as a tuple
so you can check both variants together.
Cover every case
The starter's classify match covers every Some value but omits None,
so it fails to compile with a non-exhaustive-pattern error. Add the missing
case and implement the unfinished first_pair function.
Exhaustiveness checks patterns, including the values inside a variant, not
just variant names. For example, Some(0) alone does not cover Some(1).
A guard such as if n < 0 adds a runtime condition; the exhaustiveness checker
does not count a guarded arm as covering all values of its pattern. Include
unguarded patterns that collectively cover every possible input.
Arms are considered in order. If you put a catch-all Some(n) before
Some(0), the zero arm is unreachable. After handling None, zero and
negative values, a final Some(n) can handle the remaining positive values.
Explicit variant arms also help when an enum changes: adding a variant can
expose matches that need updating. A wildcard _ already covers new variants,
so choose it when that fallback behavior is intentional.
Choose a matching form for the job
| Form | Useful when |
|---|---|
match |
Several cases each need a result or action |
if let |
One matching case needs work; the other can be skipped |
let ... else |
Later code needs a binding, and failure should leave the current path |
while let |
Repeatedly evaluate an expression while its result matches |
An ordinary let Some(n) = value; cannot handle a possible None. A
let-else can, provided its else branch diverges, for example by returning:
fn describe_value(value: Option<i32>) -> String {
let Some(n) = value else {
return "missing".to_string();
};
format!("value:{n}")
}
Here n is available after the statement. With if let, the binding is
available inside the matching branch. Pattern matching exposes a payload;
it does not change Some and None into different types.
A loop stops when its whole pattern fails
Consider an iterator of results:
let mut values = [Ok(1), Err("bad"), Ok(3)].into_iter();
let mut seen = Vec::new();
while let Some(Ok(n)) = values.next() {
seen.push(n);
}
assert_eq!(seen, vec![1]);
assert_eq!(values.next(), Some(Ok(3)));
The loop consumes the Err item and stops because that item does not match
Some(Ok(n)). It does not reach the later Ok(3) by itself. If each error
needs handling, iterate over the items and explicitly match Ok and Err.
The harness represents None as JSON null and passes integers in the
i32 range. The solution must compile, return the expected labels and pair,
and pass clippy -D warnings.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.