接受 Result<T, E> 作为函数参数是惯用的 Rust 吗?

Posted

技术标签:

【中文标题】接受 Result<T, E> 作为函数参数是惯用的 Rust 吗?【英文标题】:Is it idiomatic Rust to accept a Result<T, E> as a function argument? 【发布时间】:2020-10-08 06:27:22 【问题描述】:

考虑以下代码:

fn foo(x: i32) -> Result<i32, Error> 
    //...


fn bar(x: Result<i32,Error>) -> Result<i32, Error> 
    //...


fn main() 
    let y = bar(foo(2)).unwrap();

传递Result 类型是惯用的吗?或者您应该在直接传递i32 之前处理错误或解开bar() 的结果。

【问题讨论】:

【参考方案1】:

接受Result 作为参数是很不寻常的,除非在用于处理Results 的通用库中。

Result 具有a lot of methods,这有助于使其更符合人体工程学。例如,and_then,它将函数调用链接到先前的结果。您的示例可以更改为:

fn foo(x: i32) -> Result<i32, Error> 
    //...


fn bar(x: i32) -> Result<i32, Error> 
    //...


fn main() 
    let y = foo(2).and_then(|value| bar(value)).unwrap();

    // or more concisely in this simple case:
    let y = foo(2).and_then(bar).unwrap();

【讨论】:

【参考方案2】:

我不能说我见过的情况很有意义,但如果没有更清楚地解释你为什么要这样做,就很难提供更多帮助。

本质上,barErr() 输入有任何用处,还是直接通过它?在前一种情况下,是的,bar 采用Result 可能是有意义的——尽管你提出的问题看起来不太可能

但是,如果 bar 以类似的方式开头

fn bar(x: Result<i32, Error>) -> Result<i32, Error> 
    let y = x?;
    // work with an actual `i32` and potentially output an error as well

那就是它对Err 没有实际用途,那么不,这不是惯用的,输入是不必要且无用的复杂。

在这种情况下,您想要的是:

fn bar(x: i32) -> Result<i32, Error> 
    //...


fn main() 
    let y = foo(2).and_then(bar).unwrap();

【讨论】:

以上是关于接受 Result<T, E> 作为函数参数是惯用的 Rust 吗?的主要内容,如果未能解决你的问题,请参考以下文章

设计一个函数,它接受不定数量的参数,这是参数都是函数。这些函数都接受一个回调函数作为参数,按照回调函数被调用的顺序返回函数名

如何接受异步函数作为参数?

await Task<T> 和 Task<T>.Result 有啥区别?

Rust Diesel 原始 SQL 给出错误“`std::result::Result<Vec<T>,diesel::result::Error>` 所需的类型注释”

为啥不调用 Task<T>.Result 死锁?

使用Spring Data JPA查询时,报result returns more than one elements异常