The ? Operator
? early-returns Err (or None in Option contexts) and unwraps Ok values, with automatic conversion via From.
Search across all documentation pages
? early-returns Err (or None in Option contexts) and unwraps Ok values, with automatic conversion via From.
fn load_config(path: &str) -> Result<String, std::io::Error> {
let body = std::fs::read_to_string(path)?;
Ok(body)
}When to reach for this: Fallible functions returning Result - preferred over nested match.
#[derive(Debug)]
enum AppError {
Io(std::io::Error),
Parse(std::num::ParseIntError),
}
impl From<std::io::Error> for AppError {
fn from(e: std::io::Error) -> Self { AppError::Io(e) }
}
impl From<std::num::ParseIntError> for AppError {
fn from(e: std::num::ParseIntError) -> Self { AppError::Parse(e) }
}
fn port_from_file(path: &str) -> Result<u16, AppError> {
let text = std::fs::read_to_string(path)?;
let port: u16 = text.trim().parse()?;
Ok(port)
}What this demonstrates:
? converts io::Error and ParseIntError into AppError via FromFrom for each error source? on Result in functions returning Result expands to match with early return. In main, use fn main() -> Result<(), E>.
try_blocks (where stable) group fallible steps - check edition.
? in main without return type - Error. Fix: fn main() -> Result<(), Box<dyn Error>>.From conversion - Compile error. Fix: impl From or map manually.? on Option in Result fn - Needs compatible types or ok_or. Fix: ok_or(Error::Missing)?.? loses location. Fix: anyhow::Context or map_err.? in closures - Closure must return Result. Fix: Change closure return type.| Alternative | Use When | Don't Use When |
|---|---|---|
match | Complex recovery per error | Simple propagation |
map_err | Transform error | From already correct |
unwrap | Prototype only | Library/production |
let-else | Option guard | Result propagation |
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 16, 2026