Or by the and_then
combinator. If you need your functions to only be locally short-circuited, then a method works perfectly fine, with closures that are only run in the happy case, etc. It might be prettier with a try
block and ?
-s, but it works also without.
What doesn't work with a method is the "global short-circuiting" of early-return. This needs special support which lets you return out of the surrounding function (or a macro, like try!
was before ?
was introduced).
So your example can be written as:
fn foo() {
let some_value_i_dont_care_about_i_only_want_the_side_effect = {
some_opt_func1().and_then(|a|
some_opt_func2(a)).and_then(|b|
some_opt_func3(b)).and_then(|c|
do_something_with(c))
}
printfn!("the side effect was done only if a chain of options were all Some")
}
But this example:
fn foo() {
let some_value_i_do_care_about: MyNonOptionType = {
let a = some_opt_func1()?;
let b = some_opt_func2(a)?;
let c = some_opt_func3(b)?;
do_something_with(c)
}
println!("we get here only if a chain of options were all some");
do_something_with(some_value_i_do_care_about)
}
cannot be rewritten with methods. Hence, ?
exiting out of the function by default (which requires the function to have an appropriate return type).
And this is why you need to use ?
in Rust to bubble the errors up, instead of them explicitly poping up like exceptions. With ?
you are acknowledging that this function might fail, and expressing your unwillingness to handle the failure inside this function, delegating this to the caller. However, for this to work, you need to explicitly explain how to report this kind of error to your consumer, via a From
impl converting the error-type returned from the inner function to the one returned by the outer function. In many cases, this includes wrapping the original error, so your consumer can still inspect it:
enum MyError {
GotSystemError(SystemError),
GotNumberError(NumberError),
...
}
impl From<SystemError> for MyError {
fn from(se: SystemError) -> Self {
MyError::GotSystemError(se)
}
...
As mentioned above, there are crates made to reduce some of this boilerplate, since you prefer to know exactly what error happened, I would recommend using thiserror.