如何得到Result <t,e1 =“”>与Result <t,e2>?</t,e2> </t,>

时间:2015-03-12 23:06:22

标签: error-handling rust

我有这段代码

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")
}

我希望能够将ok().expect(..)缩减一点,以便我理想地拥有这样的东西:

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")
}

然而,这不起作用,因为错误不排成一行,让我:

    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`)

我知道错误处理在过去一个月内发生了很大的变化,我觉得应该离开让它们对齐而不会有太多麻烦。我似乎无法弄明白。

1 个答案:

答案 0 :(得分:3)

问题是传递给and_then的闭包需要返回Result,其错误类型与调用Result的{​​{1}}相同;否则,and_then没有一种类型可以返回; and_then将一个and_then类型映射到另一个,但保持错误类型相同。

由于您只是通过将错误值转换为无论如何解开的Ok选项而丢弃错误值,您可以在调用ok()之前和闭包内执行此操作,因为{{ and_then上由Option返回的1}}类型仅取决于闭包返回的值:

and_then

如果您真的关心错误值,则需要定义自己的错误类型,该错误类型可能包含两种类型的错误,并将错误包装起来。 Option特征和fn get_last_commit () -> String { Command::new("git") .arg("rev-parse") .arg("HEAD") .output() .ok() .and_then(|output| { String::from_utf8(output.stdout).ok() }) .expect("error invoking git rev-parse") } 宏提供了一种方便的方法来包装值并从函数中的几个位置之一返回它,尽管在这种情况下FromError可能会更好通过链式方法调用而不是单独的语句来完成所有操作的方法。

try!

如果您注意到,这与之前的解决方案相当接近,将两种结果类型强制转换为单一的常见类型;在第一个解决方案中,它只是通过使用map_err丢弃错误值,而在第二个解决方案中,它保留了错误值,因此您可以返回它,但是您现在需要一个可以包装的类型的额外机制