Error Handling Patterns
Question Mark
Propagating an Error
The ? operator returns early from a function when a Result is an error, and unwraps the success value otherwise.
Program
Play the program to double a selected input or report that parsing failed.
question_mark.rs
Replay: real traced execution (multi-file project)
fn double_input(text: &str) -> Result<i32, std::num::ParseIntError> {
let value = text.parse::<i32>()?;
Ok(value * 2)
}
fn main() {
let input = "21";
let result = double_input(input);
let label = match result {
Ok(value) => format!("double:{value}"),
Err(_) => "parse error".to_string(),
};
println!("{label}");
}
fn double_input(text: &str) -> Result<i32, std::num::ParseIntError> {
let value = text.parse::<i32>()?;
Ok(value * 2)
}
fn main() {
let input = "8";
let result = double_input(input);
let label = match result {
Ok(value) => format!("double:{value}"),
Err(_) => "parse error".to_string(),
};
println!("{label}");
}
fn double_input(text: &str) -> Result<i32, std::num::ParseIntError> {
let value = text.parse::<i32>()?;
Ok(value * 2)
}
fn main() {
let input = "bad";
let result = double_input(input);
let label = match result {
Ok(value) => format!("double:{value}"),
Err(_) => "parse error".to_string(),
};
println!("{label}");
}
input ← "21"
6fn main() {7 let inpu→ "21"t = "21"; //@input="21", "8", "bad"8 let result = double_input(inpu"21"t);9 let label = match result {value ← 21
1fn double_input(text: &str) -> Result<i32, std::num::ParseIntError> {2 let valu→ 21e = text.parse::<i32>()?;3 Ok(valu21e * 2)4}result ← Ok(42), label ← "double:42"
7 let input = "21"; //@input="21", "8", "bad"8 let resul→ Ok(42)t = double_input(inpu"21"t);9 let labe→ "double:42"l = match resulOk(42)t {10 Ok(value) => format!("double:{value}"),11 Err(_) => "parse error".to_string(),12 };13 println!("{label}");14}outputdouble:42
input ← "8"
6fn main() {7 let inpu→ "8"t = "8";8 let result = double_input(inpu"8"t);9 let label = match result {value ← 8
1fn double_input(text: &str) -> Result<i32, std::num::ParseIntError> {2 let valu→ 8e = text.parse::<i32>()?;3 Ok(valu8e * 2)4}result ← Ok(16), label ← "double:16"
7 let input = "8";8 let resul→ Ok(16)t = double_input(inpu"8"t);9 let labe→ "double:16"l = match resulOk(16)t {10 Ok(value) => format!("double:{value}"),11 Err(_) => "parse error".to_string(),12 };13 println!("{label}");14}outputdouble:16
input ← "bad"
6fn main() {7 let inpu→ "bad"t = "bad";8 let result = double_input(inpu"bad"t);9 let label = match result {result ← Err(ParseIntError { kind: InvalidDigit }), label ← "parse error"
7 let input = "bad";8 let resul→ Err(ParseIntError { kind: InvalidDigit })t = double_input(inpu"bad"t);9 let labe→ "parse error"l = match resulErr(ParseIntError { kind: InvalidDigit })t {10 Ok(value) => format!("double:{value}"),11 Err(_) => "parse error".to_string(),12 };13 println!("{label}");14}outputparse error
Follow the Shortcut
- The helper receives text from the caller.
- Parsing succeeds or fails.
- On success,
?gives the helper the number. - On failure,
?returns the error to the caller immediately. - The caller's
matchdecides what to display.
caller -> helper -> parse ok -> double value -> Ok(value)
caller <- helper <- parse err <- return early
?
`?` returns the error immediately or gives back the success value.
propagation
The parse error flows back to the caller as `Err`.
caller match
The caller decides how to turn the result into user-facing text.
Exercise: question_mark.rs
Use ? in a helper that parses text, doubles it, and lets the caller format both outcomes