Is there such a mechanism in Rust?
Yes - although not all in one shot, as you have already presented. Let's look at your theoretical signature:
impl<T, E> Result<T, E> { fn map_unwrap<F, U, D>(&self, op: F) -> Result<U, D> where F: FnOnce(T) -> Result<U, D>, {} }
This will not work - suppose we start with the Err
variant - how does this code know how to convert from E
to D
? Also, &self
not suitable for functions that want to convert types; usually take self
.
There are two components you need to combine:
Result::and_then
impl<T, E> Result<T, E> { fn and_then<U, F>(self, op: F) -> Result<U, E> where F: FnOnce(T) -> Result<U, E>, {} }
Result::map_err
impl<T, E> Result<T, E> { fn map_err<F, O>(self, op: O) -> Result<T, F> where O: FnOnce(E) -> F, {} }
Then you need a type that can represent both types of errors. I will be lazy and use Box<Error>
When combined with each other, you need something like:
use std::env; use std::fs::File; use std::error::Error; fn main() { let conf = env::var("CONF") .map_err(|e| Box::new(e) as Box<Error>) .and_then(|f| File::open(f).map_err(|e| Box::new(e) as Box<Error>)); }
Now each call converts the error value to a generic type, and the result is bound using and_then
. Presumably your real code will generate an error type appropriate for your problem, and then you will use this in the map_err
call. I would implement From
, then you can simply:
let conf: Result<_, Box<Error>> = env::var("CONF") .map_err(Into::into) .and_then(|f| File::open(f).map_err(Into::into));
source share