Result
: a richer version of Option
Result
is a richer version of the Option
type that
describes possible error instead of possible absence.
That is,
Result<T, E>
could have one of two outcomes:
Ok(T)
: An elementT
was foundErr(E)
: An error was found with elementE
By convention, the expected outcome is
Ok
while the unexpected outcome isErr
.
Like Option
, Result
has many methods associated with it:
unwrap()
, for example, either yields the elementT
orpanic
s.- For case handling, there are many combinators between
Result
andOption
that overlap.
In working with Rust, you will likely encounter methods that return the
Result
type, such as the parse()
method.
parse & unwrap: raise Exception
It might not always be possible to parse a string into the other type, so
parse()
returns aResult
indicating possible failure.
Let’s see what happens when we successfully and unsuccessfully parse() a string:
fn multiply(first_number_str: &str, second_number_str: &str) -> i32 { // Let's try using `unwrap()` to get the number out. Will it bite us? let first_number = first_number_str.parse::<i32>().unwrap(); let second_number = second_number_str.parse::<i32>().unwrap(); first_number * second_number } fn main() { let twenty = multiply("10", "2"); println!("double is {}", twenty); let tt = multiply("t", "2"); println!("double is {}", tt); }
- In the unsuccessful case,
parse()
leaves us with an error forunwrap()
topanic
on. - Additionally, the
panic
exits our program and provides an unpleasant error message.
Using Result
in main
To improve the quality of our error message, we should be more specific about the return type and consider explicitly handling the error.
The Result
type can also be the return type of the main
function if
specified explicitly.
Typically the main
function will be of the form:
fn main() { println!("Hello World!"); }
However main
is also able to have a return type of Result
:
- If an error occurs within the
main
function it will return an error code and print a debug representation of the error (using theDebug
trait).
The following example shows such a scenario and touches on aspects covered in the following section.
use std::num::ParseIntError; fn main() -> Result<(), ParseIntError> { let number_str = "10"; let number = match number_str.parse::<i32>() { Ok(number) => number, Err(e) => return Err(e), }; println!("{}", number); Ok(()) }