15.3 The Result
Type
While some errors demand termination, many can be anticipated and handled gracefully at runtime. Rust’s standard approach to these scenarios is the Result
type, which enforces explicit handling of both successes and failures—much like returning an error code in C, but with compile-time checks that make ignoring an error more difficult.
15.3.1 Understanding the Result
Enum
Result
is an enum defined as:
enum Result<T, E> {
Ok(T),
Err(E),
}
Ok(T)
holds a success value of typeT
.Err(E)
holds an error value of typeE
.
15.3.2 Comparing Option
and Result
Rust also provides the Option<T>
enum:
enum Option<T> {
Some(T),
None,
}
Option<T>
expresses the possibility of an absence of a value (not necessarily an error).Result<T, E>
expresses an operation that might fail and produce error information.
15.3.3 Basic Use of the Result
Type
Here’s a simple example that parses two strings into integers and multiplies them:
use std::num::ParseIntError; fn multiply(first_str: &str, second_str: &str) -> Result<i32, ParseIntError> { match first_str.parse::<i32>() { Ok(first_number) => match second_str.parse::<i32>() { Ok(second_number) => Ok(first_number * second_number), Err(e) => Err(e), }, Err(e) => Err(e), } } fn main() { println!("{:?}", multiply("10", "2")); // Ok(20) println!("{:?}", multiply("x", "y")); // Err(ParseIntError(...)) }
To reduce nesting, you can use and_then
and map
:
use std::num::ParseIntError; fn multiply(first_str: &str, second_str: &str) -> Result<i32, ParseIntError> { first_str.parse::<i32>().and_then(|first_number| { second_str.parse::<i32>().map(|second_number| first_number * second_number) }) } fn main() { println!("{:?}", multiply("10", "2")); // Ok(20) println!("{:?}", multiply("x", "y")); // Err(ParseIntError(...)) }
15.3.4 Using Result
in main()
While main()
normally returns ()
, you can also have it return a Result
:
use std::num::ParseIntError; fn main() -> Result<(), ParseIntError> { let number_str = "10"; let number = number_str.parse::<i32>()?; println!("{}", number); Ok(()) }
An error will cause the program to exit with a non-zero code, whereas returning Ok(())
exits with code 0.