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.