I have this code
fn get_last_commit () -> String {
Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()
.map(|output| {
String::from_utf8(output.stdout).ok().expect("error reading into string")
})
.ok().expect("error invoking git rev-parse")
}
I'd like to be able to cut the ok().expect(..)
a bit down so that I ideally have something like that:
fn get_last_commit () -> String {
Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()
.and_then(|output| {
String::from_utf8(output.stdout)
})
.ok().expect("error invoking git rev-parse")
}
However, that doesn't work because the errors don't line up leaving me with:
mismatched types:
expected `core::result::Result<_, std::io::error::Error>`,
found `core::result::Result<collections::string::String, collections::string::FromUtf8Error>`
(expected struct `std::io::error::Error`,
found struct `collections::string::FromUtf8Error`)
I know the error handling changed quite a bit within the last month and I have the feeling there should be away to get them aligned without too much hassle. I seem unable to figure it out though.
The problem is that the closure passed to the
and_then
needs to return aResult
with the same error type as theResult
thatand_then
was called on; otherwise, there's no single type thatand_then
could return;and_then
maps oneOk
type to another, but keeps the error type the same.Since you are just throwing away the error value by converting it to an option with
ok()
that you unwrap anyhow, you can do that before callingand_then
, and within the closure, as theOption
type returned byand_then
on anOption
only depends on the value returned by the closure:If you actually cared about the error value, you would need to define your own error type that could contain either of the two types of errors, and wrap either of the errors up. The
FromError
trait andtry!
macro offer a convenient way to is wrap up the value and return it from one of several places in your function, though in this casemap_err
would probably be a better way to do that as you are doing it all via chained method calls rather than separate statements.If you notice, this parallels the earlier solution fairly closely, coercing both of the result types into a single common type; in the first solution, it just throws away the error value by using
ok()
, while in the second, it preserves the error value so you can return it, but you now need the extra machinery of a type that could wrap either.