Propagating Errors with ?
Reading a loan request means several steps that can fail: parse the card number, parse the number of days, look up the book. Writing a full match for each step buries the real logic. Usually the function should just stop and let its caller deal with the problem. Rust has a single character for that.
The rule
?unwraps success, or returns the failure from this function.
Without ?:
use std::num::ParseIntError;
fn parse_days(input: &str) -> Result<u32, ParseIntError> {
let days = match input.trim().parse::<u32>() {
Ok(d) => d,
Err(e) => return Err(e),
};
Ok(days.min(21))
}With ?, the same function:
fn parse_days(input: &str) -> Result<u32, ParseIntError> {
let days = input.trim().parse::<u32>()?;
Ok(days.min(21))
}What ? does on a Result:
Ok(v)→ the expression becomesv, and the function carries on.Err(e)→ the function returns immediately withErr(e). If the function's error type differs,?first convertsewithFrom::from(next lesson uses this).
On an Option, ? returns None early instead.
Where ? is allowed: only in a function whose return type can carry the failure: a Result for Result values, an Option for Option values. A plain fn main() returns (), so ? there is a compile error. The fix is to let main return a Result:
fn main() -> Result<(), ParseIntError> {
let days = parse_days("14")?;
println!("loan for {days} days");
Ok(())
}If main returns an Err, the program prints the error (in its Debug form) and exits with a failure code.
The shortcut
Read every ? aloud as "or bail out": "parse the days, or bail out". Then check the signature: can this function bail out with that kind of failure?
Signature first
fn parse_request(card: &str, days: &str) -> Result<(u32, u32), ParseIntError>: it can bail out with aParseIntError.
The trap is forgetting the final Ok(...). The last line must wrap the success value, because the function returns a Result, not a bare tuple.
Drills
Answer fast — trust the rule.
In let d = "14".parse::<u32>()?;, what is d when parsing succeeds?
What does ? do when the parse returns Err?
Why does ? inside a plain fn main() { ... } fail to compile?
A function returns Option<Book>. What does ? on a None inside it do?
Remember
?gives the success value or returns the failure early, converting the error withFromif needed.- Read it as "or bail out", and check the function's return type can carry that failure.
- Trap:
?in a function returning(), and forgetting the finalOk(...).
