如何简洁地组合多个不同类型的“Result”?

9

目前我使用的是这种模式:

let a: Result<A, ParseError> = parseA();
let b: Result<B, ParseError> = parseB();
let c: Result<C, ParseError> = parseC();
a.and_then(|a| b.map(|b| (a, b))).and_then(|(a,b)| c.map(|c| {
  // finally the crux of what I want to do
  a.foo(b).bar(c)
}))

有没有更简洁的方法来定义abc,比如Scala的for表达式?


1
这并不完全是“合并结果”,就像你在这里尝试的那样...然而,最近我一直在将解析与迭代结合起来,在将所有内容汇总时进行合并。但我不确定这是否适合您,因为在这种情况下很难知道哪一个失败了(如果有的话)。 - Simon Whitehead
我喜欢它。虽然它不是我所需要的,并让我意识到我的问题有点误导。我将再次尝试编写它。 - Synesso
1个回答

5

我通常将所有内容都包裹在层中,而不是通过元组进行链接:

let result = a.and_then(|a| {
    b.and_then(|b| {
        c.map(|c| {
            a.foo(b).bar(c)
        })
    })
});

或者,在最近的Rust版本中,你可以精心利用?运算符:

let result = a.and_then(|a| {
    a.foo(b?).bar(c?)
});

闭包可以让你以一种优雅而安全的方式实现这个功能。
当然,如果你想将中间结果存储在变量中,这种方法就不起作用了。

a?.foo(b?).bar(c?) 也能行吗?或者甚至可以这样:parseA()?.foo(parseB()?).bar(parseC()?),后者如果 parseA 失败,则不执行 parseB,以此类推。 - user4815162342
2
只有在您的函数返回 Result 时才可以这样做。如果您想手动处理它,则不能这么做。即使您返回 Result,您也需要在 Ok(a?.foo(b?))a.and_then(|a| a.foo(b?)) 之间做出决定,这取决于您的实际代码可能会导致后者更易读(在 serde 中我们经常遇到这种情况)。 - oli_obk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接