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(())
}​