How do I know what error happened when piping Result
s via and_then
in Rust? For example using nested matches I could do this:
use std::num::ParseIntError;
fn get_num(n: u8) -> Result<u8, ParseIntError> {
// Force a ParseIntError
"foo ".parse()
}
fn add_one(n: u8) -> Result<u8, ParseIntError> {
Ok(n + 1)
}
fn main() {
match get_num(1) {
Ok(n) => {
match add_one(n) {
Ok(n) => println!("adding one gives us: {}", n),
Err(why) => println!("Error adding: {}", why)
}
},
Err(why) => println!("Error getting number: {}", why),
}
}
Or I can use and_then
to pipe the result of the first function to the second and avoid a nested match:
match get_num(1).and_then(add_one) {
Ok(n) => println!("Adding one gives us: {}", n),
Err(why) => println!("Some error: {}.", why)
}
How do I conditionally and idiomatically determine the error in the second form, using and_then
? Do I have to type check the error? Sure I can display the error like I did above, but let's say I want to preface it with something related to the kind of error it is?
The normal way would be to use map_err
to convert the initial errors to something richer you control e.g.
enum MyError {
Parsing,
Adding
}
get_num(1).map_err(|_| MyError::Parsing)
.and_then(|v| add_one(v).map_err(|_| MyError::Adding)
sadly as you can see this requires using a lambda for the and_then
callback: and_then
must return the same error type as the input, so here it has to yield a Result<_, MyError>
, wjhich is not the return type of add_one
.
And while in other situations we could recover somewhat with ?
, here the same original error type is split into two different values.