result
Error handling with the Result
type.Result
is the type used for returning and propagating errors. It is an enum with the variants, Ok(T)
, representing success and containing a value, and Err(E)
, representing error and containing an error value.
enum Result<T, E> {
Ok: T,
Err: E,
}
Functions return Result
whenever errors are expected and recoverable.A simple function returning Result
might be defined and used like so:
fn parse_version(header: felt252) -> Result<felt252, felt252> {
match header {
0 => Ok(0),
1 => Ok(1),
_ => Err('invalid version'),
}
}
let version = parse_version(1);
match version {
Ok(v) => println!("working with version {}", v),
Err(e) => println!("error parsing version: {:?}", e)
}
Results must be usedA common problem with using return values to indicate errors is that it is easy to ignore the return value, thus failing to handle the error. Result
is annotated with the #[must_use]
attribute, which will cause the compiler to issue a warning when a Result value is ignored. # Method overviewIn addition to working with pattern matching, Result
provides a wide variety of different methods. ## Querying the variantThe is_ok
and is_err
methods return true
if the Result
is Ok
or Err
, respectively. ## Extracting contained valuesThese methods extract the contained value in a [Result<T, E>
](Result<T, E>
) when it is the Ok
variant. If the Result
is Err
:expect
panics with a provided felt252 error message * unwrap
panics with a generic message * unwrap_or
returns the provided default value * unwrap_or_default
returns the default value of the type T
(which must implement the Default
trait) * unwrap_or_else
returns the result of evaluating the provided functionexpect
: ResultTrait::expect unwrap
: ResultTrait::unwrap unwrap_or
: ResultTrait::unwrap_or unwrap_or_default
: ResultTrait::unwrap_or_default unwrap_or_else
: ResultTrait::unwrap_or_elseThese methods extract the contained value in a [Result<T, E>
](Result<T, E>
) when it is the Err
variant. If the Result
is Ok
:expect_err
panics with a provided felt252 error message * unwrap_err
panics with a generic messageexpect_err
: ResultTrait::expect_err unwrap_err
: ResultTrait::unwrap_err ## Transforming contained valuesThese methods transform Result
to Option
:ok
transforms [Result<T, E>
](Result<T, E>
) into Option<T>
, mapping Ok(v)
to Some(v)
and Err(e)
to None
* err
transforms [Result<T, E>
](Result<T, E>
) into Option<E>
, mapping Ok(v)
to None
and Err(e)
to Some(e)
This method transforms the contained value of the Ok
variant:map
transforms [Result<T, E>
](Result<T, E>
) into [Result<U, E>
](Result<U, E>
) by applying the provided function to the contained value of Ok
and leaving Err
values unchangedThis method transforms the contained value of the Err
variant:map_err
transforms [Result<T, E>
](Result<T, E>
) into [Result<T, F>
](Result<T, F>
) by applying the provided function to the contained value of Err
and leaving Ok
values unchangedThese methods transform a [Result<T, E>
](Result<T, E>
) into a value of a possibly different type U
:map_or
applies the provided function to the contained value of Ok
, or returns the provided default value if the Result
is Err
* map_or_else
applies the provided function to the contained value of Ok
, or applies the provided default fallback function to the contained value of Err
map_or
: ResultTrait::map_or map_or_else
: ResultTrait::map_or_else ## Boolean operatorsThese methods treat the Result
as a boolean value, where Ok
acts like true
and Err
acts like false
. There are two categories of these methods: ones that take a Result
as input, and ones that take a function as input.The and
and or
methods take another Result
as input, and produce a Result
as output. The and
method can produce a [Result<U, E>
](Result<U, E>
) value having a different inner type U
than [Result<T, E>
](Result<T, E>
). The or
method can produce a [Result<T, F>
](Result<T, F>
) value having a different error type F
than [Result<T, E>
](Result<T, E>
).| method | self | input | output | |---------|----------|-----------|----------| | and
| Err(e)
| (ignored) | Err(e)
| | and
| Ok(x)
| Err(d)
| Err(d)
| | and
| Ok(x)
| Ok(y)
| Ok(y)
| | or
| Err(e)
| Err(d)
| Err(d)
| | or
| Err(e)
| Ok(y)
| Ok(y)
| | or
| Ok(x)
| (ignored) | Ok(x)
|and
: ResultTrait::and or
: ResultTrait::orThe and_then
and or_else
methods take a function as input, and only evaluate the function when they need to produce a new value. The and_then
method can produce a [Result<U, E>
](Result<U, E>
) value having a different inner type U
than [Result<T, E>
](Result<T, E>
). The or_else
method can produce a [Result<T, F>
](Result<T, F>
) value having a different error type F
than [Result<T, E>
](Result<T, E>
).| method | self | function input | function result | output | |--------------|----------|----------------|-----------------|----------| | and_then
| Err(e)
| (not provided) | (not evaluated) | Err(e)
| | and_then
| Ok(x)
| x
| Err(d)
| Err(d)
| | and_then
| Ok(x)
| x
| Ok(y)
| Ok(y)
| | or_else
| Err(e)
| e
| Err(d)
| Err(d)
| | or_else
| Err(e)
| e
| Ok(y)
| Ok(y)
| | or_else
| Ok(x)
| (not provided) | (not evaluated) | Ok(x)
|and_then
: ResultTrait::and_then or_else
: ResultTrait::or_else # The question mark operator, ?
When writing code that calls many functions that return the Result
type, handling Ok
/Err
can be tedious. The question mark operator, ?
, hides some of the boilerplate of propagating errors up the call stack.It replaces this:
use core::integer::u8_overflowing_add;
fn add_three_numbers(a: u8, b: u8, c: u8) -> Result<u8, u8> {
match u8_overflowing_add(a, b) {
Ok(sum_ab) => {
match u8_overflowing_add(sum_ab, c) {
Ok(total) => Ok(total),
Err(e) => Err(e),
}
},
Err(e) => Err(e),
}
}
With this:
use core::integer::u8_overflowing_add;
fn add_three_numbers_2(a: u8, b: u8, c: u8) -> Result<u8, u8> {
let total = u8_overflowing_add(u8_overflowing_add(a, b)?, c)?;
Ok(total)
}
It's much nicer: Ok
Err
: Err ## Iterating over Result
A Result
can be iterated over. This can be helpful if you need an iterator that is conditionally empty. The iterator will either produce a single value (when the Result
is Ok
), or produce no values (when the Result
is Err
). For example, into_iter
contains Some(v)
if the Result
is Ok(v)
, and None
if the Result
is Err
.
Fully qualified path: core::result