may_fail_who_knows()
.map(use_value)
.map_err(some_error_processing)
.and_then(another_computation_which_can_fail)
.or_else(with_some_error_handling_that_can_rescue)
.unwrap_or(a_default_value)
Basically, instead of nested match expressions, you get a "pipeline". let x = match may_fail_who_knows() {
Ok(y) => Ok(another_computation_which_can_fail(use_value(x))),
Err(e) => with_some_error_handling_that_can_rescue(
some_error_processing(e)),
};
match x {
Ok(y) => y,
_ => a_default_value,
}
It's a bit more verbose than using the combinators, but someone coming across it for the first time will understand it immediately because there's less to remember to understand it (this is where go really shines).Also: by avoiding functors there are fewer subtle lifetime issues and `move ||` stuff to deal with and you can return from the containing function and use the `?` operator.
During the discussions of how `.await` was going to work for rust async there was the proposal to add other suffix keywords. So this would look like:
may_fail_who_knows()
.match {
Ok(y) => Ok(another_computation_which_can_fail(use_value(x))),
Err(e) => with_some_error_handling_that_can_rescue(
some_error_processing(e)),
}
.match {
Ok(y) => y,
_ => a_default_value,
}
Maybe not that different.You just had to write the concrete types (Ok and Err) out. What if these types are changed later on, e.g. to "Some(...)" and "None" or "Ok" and "ManyErrs(...)"?
As you said, it is easier to understand. Because it less abstract. This can be a good thing, but as well be a bad thing - but one thing is sure: while it does the same in the concrete case, the code is not "equivalent" when it comes to refactoring and certain changes.
match may_fail_who_knows() {
Ok(success) => {
do_something_with_success(success)?
},
Err(failed) => {
some_error_processing(failed)
}
}
As `do_something_with_success` in a closure can't early return from the function (since it's in a closure), which makes sense, but just annoying to read nested results. let result = may_fail_who_knows()?
.use_value_which_might_also_fail()?
.use_a_different_way_that_might_fail()?;