Reputation: 6447
The Result
docs give the following explanation for the .or_else()
method:
fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F>
Calls op if the result is Err, otherwise returns the Ok value of self.
This function can be used for control flow based on result values.
Examples
fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
fn err(x: u32) -> Result<u32, u32> { Err(x) }
assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));
assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));
assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));
assert_eq!(Err(3).or_else(err).or_else(err), Err(3));
I think can parse the or_else
type annotation with more whitespace:
fn or_else<F, // F being the return type of the Result?
O: FnOnce(E) -> Result<T, F> // the function to run instead if error
>
(self, op: O) // arguments to the `.or_else()` method
-> Result<T, F> // return type is again Result
Assuming I've got that right, does that mean .or_else()
simply gives you a Result
with the Error
replaced with the return value of the op
function?
I can understand returning a Result
yet again, since all code downstream of possibly error-throwing code is "stained" with the possibility of further errors (and it's up to the caller to handle that). But why the doubled calls in the examples? There are a couple different permutations, but I'm not sure what they're trying to show (or if that doubled or_else()
pattern is idiomatic).
Upvotes: 0
Views: 221
Reputation: 34145
The example may be a bit unfortunate, because it tries to show at the same time how does or_else
work, and why would you use it.
To split it into two parts. First what does or_else
actually do. If you get call it on Ok
value, it passes the Ok
value. If you call it on Err
value, it executes the function. This example should be enough:
Ok(2).or_else(sq), Ok(2) // not called
Ok(2).or_else(err), Ok(2) // not called
Err(2).or_else(sq), Ok(4) // called, succeeds
Err(2).or_else(err), Err(3) // called, fails
Now, the why would you use it part. Imagine you're doing some operation which has many alternative approaches. For example you're trying to install some package on linux, but don't care which package manager is available - you're just going to brute-force it. With all the functions returning Result<...>
you could do this:
install_with_apt().
or_else(install_with_yum).
or_else(install_with_pacman).
or_else(install_with_dnf).
or_else...
You'll know that if you got back Ok
, at least one of those succeeded and if you get back Err
all of them failed. The doubled .or_else()
usage in the example if likely just trying to show you can easily chain this call.
Upvotes: 8