Best way to map Result<T, E> to Result<T, F> where F is a literal

I'm aware of the following methods

let a: u32 = "1".parse().map_err(|_| "Invalid arg")?;
let b: u32 = "2".parse().ok().ok_or("Invalid arg")?;
let c: u32 = "3".parse().or(Err("Invalid arg"))?;

However, I've noticed the Option type already has the straightforward .ok_or(literal), is there a reason why Result doesn't implement this method? And what would be another direct approach than the ones mentioned above?

If you want to map the error part of the result, definitely use .map_err(), the other variants don't convey that intent.

The Option::ok_or method is meant for converting an Option into a Result. Thus, there's no logical direct counterpart to it for Result since you already have one.

3 Likes

Thanks, would be great if there was anything like .map_err() that accepts the error directly instead of a callback (like many other similar methods), but seems like .map_err() will have to do it for now.

If you want to keep the underlying error but wrap it in your own custom error, a common pattern is this

enum MyError {
    ParseError(std::num::ParseIntError)
}
“1”.parse().map_err(MyError::ParseError)

This is less noisy and works because the constructor for MyError::ParseError is effectively a single argument function that takes the underlying error as an argument and returns a MyError. This also has the benefit of keeping the underlying error which may have useful additional information.

The difference is that here we (may) already have some error value, and discarding and replacing it with another should probably stand out in code. I guess there could be something like replace_err(othererror), but map_err(|_| othererror) works just as well, and the idiomatic |_| makes it clear that the previous value is being discarded.