Use `?` in functions that return `Result` to keep the successful value and return early on an error. It replaces repetitive error checks when propagation is the right response. Functions that may have no value can instead return `Option`, allowing `?` to propagate absence. section 4.6 section 6.1
fn read_file(name: &str) -> Result<String, Error> {
use std::fs::File;
use std::io::prelude::*;
let mut file = File::open(name)?; #1
let mut contents = String::new();
file.read_to_string(&mut contents)?; #2
Ok(contents)
}
The file-reading function uses `?` after both `File::open` and `read_to_string`. If either operation fails, the function returns early; otherwise, it returns the file contents. section 4.6
impl From<std::io::Error> for Error {
fn from(other: std::io::Error) -> Self {
Self {
message: other.to_string(),
}
}
}
Both file operations produce `std::io::Error`, but the function returns its own `Error` type. This `From` implementation supplies the conversion needed at each `?`. section 4.6
Use propagation deliberately:
- Return a crate-specific error type when callers need to identify where an error originated, and provide `From` conversions for errors passed through `?`. section 4.6
- Handle an error explicitly when the response depends on the particular function; `?` is most useful for generic propagation. section 6.1
- Use `expect()` with an explanatory message if an unexpected result should panic, rather than treating it as an error to propagate. section 6.1



