The ? Operator
The ? operator is used to propagate errors in functions that return a Result type. It is a shorthand for handling Result and Option types in a way that simplifies error handling and makes the code more readable.
Usage of ?
When you use the ? operator on a Result or Option value, it does the following:
- If the value is
Ok(T)orSome(T), it unwraps the value and continues execution. - If the value is
Err(E)orNone, it returns early from the function with the error.
Here is an example:
fn process_file(path: &str) -> Result<(), std::io::Error> {
let mut file = std::fs::File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
println!("File contents: {}", contents);
Ok(())
}
In this example:
File::open(path)?attempts to open the file. If it fails, it returns the error immediately.file.read_to_string(&mut contents)?attempts to read the file contents. If it fails, it returns the error immediately.- If both operations succeed, it prints the contents and returns
Ok(()).
Ok(())
Ok(()) is a Result type where the success value is a unit type (). This is often used to indicate that a function has completed successfully without returning any specific value.
Meaning of Ok(())
Ok: Indicates that the operation was successful.(): The unit type, which represents an empty tuple. It is used when there is no meaningful value to return.
In the context of the process_file function above, Ok(()) indicates that the function has completed successfully and there are no errors.
Example
Here is a complete example to illustrate the usage of ? and Ok(()):
use std::fs::File;
use std::io::{self, Read};
fn read_file_contents(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn main() {
match read_file_contents("example.txt") {
Ok(contents) => println!("File contents: {}", contents),
Err(e) => println!("Failed to read file: {}", e),
}
}
In this example:
File::open(path)?andfile.read_to_string(&mut contents)?use the?operator to propagate errors.- If both operations succeed,
Ok(contents)is returned. - In the main function, the result is handled using a match statement.
Summary
The ? operator is used to propagate errors in functions that return a Result or Option type. Ok(()) is a Result type indicating successful completion without returning any specific value. Using ? and Ok(()) helps make error handling in Rust more concise and readable.