Error handling in Rust is based on the concept of "
recoverable" errors, where errors are represented using the `
Result<T, E>` type. This approach encourages explicit handling of errors and helps prevent runtime errors and unexpected panics.
The `
Result<T, E>` type is an enumeration with two variants:
* `Ok(T)`: Represents a successful result with a value of type `
T`.
* `Err(E)`: Represents an error condition with an associated value of type `
E`.
Here's an overview of how error handling works in Rust:
1. Returning Results : Functions that can produce errors typically return `
Result<T, E>`. By convention, the `Result` type is used to indicate that an operation can result in either a successful value (`
Ok`) or an error (`
Err`).
Example :
fn parse_number(s: &str) -> Result<i32, ParseIntError> {
match s.parse::<i32>() {
Ok(num) => Ok(num),
Err(err) => Err(err),
}
}
2. Propagating Errors : When calling a function that returns `
Result`, you have to handle the potential errors. You can either use pattern matching (`match`), or you can utilize the `
?` operator, known as the "
try" operator, to propagate errors.
Example using `match`:
fn double_number(s: &str) -> Result<i32, ParseIntError> {
let num = match parse_number(s) {
Ok(num) => num * 2,
Err(err) => return Err(err),
};
Ok(num)
}
Example using `?` operator :
fn double_number(s: &str) -> Result<i32, ParseIntError> {
let num = parse_number(s)?;
Ok(num * 2)
}
The `
?` operator unwraps the `
Result` value and returns the underlying value if it's `
Ok`. If the value is `
Err`, the `
?` operator short-circuits the function, returning the `
Err` value from the enclosing function.
3. Error Handling with `match`: Pattern matching (`
match`) is commonly used to handle different error conditions explicitly. You can match on specific error variants and execute specific code blocks based on the error type.
Example :
fn handle_error(result: Result<i32, ParseIntError>) {
match result {
Ok(num) => println!("Parsed number: {}", num),
Err(ParseIntError { .. }) => println!("Failed to parse integer"),
}
}
4. Propagating Errors with `?` in `main()`: When handling errors in the `
main()` function, you can use the `
?` operator to automatically propagate errors, which will cause the program to exit and display the error if one occurs.
Example :
fn main() -> Result<(), Box<dyn Error>> {
let result = double_number("42")?;
println!("Doubled number: {}", result);
Ok(())
}