2 · Model and validate · 25 MIN
Enums and exhaustive decisions
An enum lists valid states and the data belonging to each state.
Option<T> represents a value that may be absent. match requires every possible variant to be handled, so forgetting the absence branch becomes a compiler error instead of a runtime surprise. This sample finds the first passing score without using a sentinel value that could conflict with a real score. Pattern matching can also model loading, success and failure states with different associated data. Avoid unwrap on external input: absence may be ordinary behavior rather than a program defect.
Model absence in the type instead of returning -1.
Read the example
fn first_pass(scores: &[i32]) -> Option<i32> {
scores.iter().copied().find(|score| *score >= 60)
}
fn main() {
for scores in [&[40,60,90][..], &[][..]] {
match first_pass(scores) {
Some(value) => println!("pass={value}"),
None => println!("no pass"),
}
}
}Check the expected output
pass=60 no pass
Your challenge
Define an enum for Pending, Success with a score, and Failed with a message; render every state with match.
Solution cost: O(n) worst case, stopping at the first match. time · Account for collection storage separately from the returned result. space
Common trap
A wildcard arm can hide future variants that deserve explicit behavior.
Study the project implementation
fn first_pass(scores: &[i32]) -> Option<i32> {
scores.iter().copied().find(|score| *score >= 60)
}
fn main() {
for scores in [&[40,60,90][..], &[][..]] {
match first_pass(scores) {
Some(value) => println!("pass={value}"),
None => println!("no pass"),
}
}
}Further reading: Official documentation
Next lesson: Result and error propagation →