The generic Result<T, E>
enum serves to transmit a recoverable error. It is used to return a
value from a function when an error is possible. The enum is made to
transport either the value through its Ok(T) variant or the error
through its Err(E) variant.
The definition of the Result<T, E> enum is as following:
enum Result<T, E> {
Ok(T),
Err(E),
}Some of the methods of Result<T, E> are presented in
Table 1. See
Result<T, E> for
a full list.
Table 1:Some methods of Result<T, E>
Method | Description |
|---|---|
| Returns |
| Returns |
| Convert a |
| Convert a |
| Converts |
| Returns |
| Returns a |
| Calls function |
| Returns |
| Returns |
| Returns an iterator on the possibly contained value. |
| Returns a mutable iterator on the possibly contained value. |
| Maps the function |
| Maps the function |
| Transforms the |
| Returns this result if it contains a value, otherwise returns
|
| Returns this result if it contains a value, otherwise calls |
| Transposes a |
| Returns the current value |
| Returns the current value |
| Returns the current value |
33.2.1Returning a Result¶
Using Result we can now return an error from a function. Here is an
implementation of the factorial that takes a signed integer. We
handle the case of negative values by returning an Err value, while we
return an Ok value for the normal case:
fn fact(n: i64) -> Result<i64, &'static str> {
if n == 0 {
Ok(1)
} else if n < 0 {
Err("Cannot compute factorial of a negative number.")
} else {
fact(n-1).map(|k| k * n)
}
}Here is the result of the function on two integers, one negative and one positive:
(fact(-2), fact(11))(Err("Cannot compute factorial of a negative number."), Ok(39916800))33.2.2Handling a Result¶
Using the match keyword we can handle the two cases of the Result
enum:
for n in [5, -10] {
match fact(n) {
Ok(f) => println!("{n}! = {f}"),
Err(e) => println!("Factorial error: {e}"),
}
}5! = 120
Factorial error: Cannot compute factorial of a negative number.
()33.2.3Unwrapping¶
Like Option, Result offers methods to unwrap the contained value,
or handle the error.
Using unwrap() we can get the value directly but it will trigger a
panic if it is an error. In the following example we try to open the
file hello.txt for reading, but it will fail if the file does not
exist:
fn foo() -> Result<i32, &'static str> {
Err("Unrecoverable error")
}
foo().unwrap()
thread '<unnamed>' (43169) panicked at src/lib.rs:35:7:
called `Result::unwrap()` on an `Err` value: "Unrecoverable error"
stack backtrace:
0: __rustc::rust_begin_unwind
at /rustc/58cf8f9c35b355199727627d07ae34a4e2846d67/library/std/src/panicking.rs:679:5
1: core::panicking::panic_fmt
at /rustc/58cf8f9c35b355199727627d07ae34a4e2846d67/library/core/src/panicking.rs:80:14
2: core::result::unwrap_failed
at /rustc/58cf8f9c35b355199727627d07ae34a4e2846d67/library/core/src/result.rs:1871:5
3: __rust_try
4: run_user_code_3
5: <evcxr::runtime::Runtime>::run_loop
6: evcxr::runtime::runtime_hook
7: evcxr_jupyter::main
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
We may use expect() to customize the error message:
fn foo() -> Result<i32, &'static str> {
Err("Unrecoverable error")
}
foo().expect("Error when calling foo()")
thread '<unnamed>' (43169) panicked at src/lib.rs:35:7:
Error when calling foo(): "Unrecoverable error"
Instead of panicking, we may use the unwrap_or() method to return a
default value:
fn foo() -> Result<i32, &'static str> {
Err("Unrecoverable error")
}
foo().unwrap_or(1)1Or use the unwrap_or_else() method to call a closure that returns a
computed default value:
fn foo() -> Result<i32, &'static str> {
Err("Unrecoverable error")
}
foo().unwrap_or_else(|e| { println!("{e}") ; 0 })Unrecoverable error
0