As you may have noticed, Rust does not have exceptions. It has panics, but their use for error-handling is discouraged (they are meant for unrecoverable errors).
In Rust, error handling uses Result
. A typical example would be:
fn halves_if_even(i: i32) -> Result<i32, Error> {
if i % 2 == 0 {
Ok(i / 2)
} else {
Err(/* something */)
}
}
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = match halves_if_even(i) {
Ok(i) => i,
Err(e) => return Err(e),
};
// use `i`
}
This is great because:
It's less than ideal, however, in that it is very verbose. This is where the question mark operator ?
comes in.
The above can be rewritten as:
fn do_the_thing(i: i32) -> Result<i32, Error> {
let i = halves_if_even(i)?;
// use `i`
}
which is much more concise.
What ?
does here is equivalent to the match
statement above with an addition. In short:
Result
if OKInto::into
on the error value to potentially convert it to another type.It's a bit magic, but error handling needs some magic to cut down the boilerplate, and unlike exceptions it is immediately visible which function calls may or may not error out: those that are adorned with ?
.
One example of the magic is that this also works for Option
:
// Assume
// fn halves_if_even(i: i32) -> Option<i32>
fn do_the_thing(i: i32) -> Option<i32> {
let i = halves_if_even(i)?;
// use `i`
}
The ?
operator, stabilized in Rust version 1.13.0 is powered by the (unstable) Try
trait.
See also:
It is for error propagation for recoverable error type Result<T, E>
. It unwraps the result and gives you the inner value.
Rather than handling error case, you propagate it to the caller code and deal with only the Ok
case. Benefit is, it eliminates a lot of boilerplate and makes function's implementation simpler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With