The ? Operator
Chaining .and_then() works, but gets verbose. Rust's ? operator is syntactic sugar for error propagation.
Before: manual matching
fn read_config() -> Result<Config, Error> {
let file = match File::open("config.txt") {
Ok(f) => f,
Err(e) => return Err(e),
};
let contents = match read_to_string(file) {
Ok(s) => s,
Err(e) => return Err(e),
};
parse_config(&contents)
}
After: with ?
fn read_config() -> Result<Config, Error> {
let file = File::open("config.txt")?;
let contents = read_to_string(file)?;
parse_config(&contents)
}
The ? does exactly what the match did: if Ok, unwrap the value; if Err, return early with the error.
Python comparison
In Python, exceptions propagate automatically:
def read_config():
file = open("config.txt") # raises if fails
contents = file.read() # raises if fails
return parse_config(contents)
Rust's ? gives you the same concise code, but the error handling is explicit in the return type.
? works with Option too
fn get_first_char(s: Option<String>) -> Option<char> {
let text = s?; // return None if s is None
text.chars().next()
}
The return type must match
? only works when the function returns Result or Option. This won't compile:
fn main() {
let f = File::open("test.txt")?; // ERROR: main returns ()
}
Fix: use .unwrap(), .expect(), or change the return type.
Error conversion with From
If your function returns Result<T, MyError> but you call something that returns Result<T, OtherError>, Rust can convert automatically if MyError: From<OtherError>:
impl From<io::Error> for MyError {
fn from(e: io::Error) -> Self {
MyError::Io(e)
}
}
Login to see the full task and start coding.
This is a premium exercise
Log in to unlock the full exercise and start coding.
Login to access this exercise