Put `?` after an expression that returns a `Result` when you want to pass an error back to the caller. With `Ok`, it gives you the value inside and continues. With `Err`, it returns the error immediately, so later lines do not run. It also works with `Option`: a value inside `Some` continues, while `None` returns early. section 6.2
Parse, then continue
In a function returning `Result<i32, ParseIntError>`, `let number = input.parse::<i32>()?;` gets the number if parsing succeeds. A following success message runs only in that case. Finish with `Ok(number)`: `?` gives you an `i32` on success, but the function still promises to return a `Result`. section 6.2
use std::num::ParseIntError;
fn parse_and_log_str(input: &str) -> Result<i32, ParseIntError> {
let parsed_number = match input.parse::<i32>() {
Ok(number) => number,
Err(e) => return Err(e),
};
println!("Number parsed successfully into {parsed_number}");
Ok(parsed_number)
}
Compare the longer `match` with `?`: its `Ok` arm takes the number, and its `Err` arm returns the error before printing the success message. section 6.2
The function using `?` must have a suitable return type. `main` can return `Result<(), ParseIntError>` when it uses `?` while parsing; if parsing fails inside a loop, it returns before reaching later items. When operations can produce different error types, choosing a shared error type needs more thought. One application returns `Result<(), Box<dyn Error>>`; another uses `anyhow::Error`. section 6.2 section 23.3.3 section 23.4.3
This is especially handy for file operations, where opening or reading may fail. It can also replace `.unwrap()` during cleanup when errors should be returned rather than cause a panic. In asynchronous code, error handling often appears as `.await?`. section 18.3 section 23.3.3 section 19.3.3



