rust - 有没有办法链接结果映射和展开?

标签 rust

我有这个代码。

if let Ok(file) = env::var("CONF") {
    if let Ok(mut reader) = fs::File::open(&file) {
        if let Ok(conf) = Json::from_reader(&mut reader) {
            // do something with conf
        }
    }
}

我试图让它不像节日树那样,并且正在考虑链接。请注意,此链中的每个步骤都会产生另一个 Result,因此显然这是行不通的(我们在 Result 中得到了 Result)。

let conf = env::var("CONF")
    .map(fs::File::open)
    .map(Json::from_reader);

// do something with conf

我的错误类型也因每个步骤而异,这意味着我不能只将 .map 替换为 .and_then

我想我正在寻找类似于 JavaScript 的 promise 的东西。也就是说,从 promise 内部返回的 promise 解开了内部 promise。签名可能应该是这样的:

impl<T, E> Result<T, E> {
    fn map_unwrap<F, U, D>(&self, op: F) -> Result<U, D>
        where F: FnOnce(T) -> Result<U, D>
}

Rust 有这样的机制吗?还有其他方法可以摆脱我的节日树吗?

最佳答案

Is there such a mechanism in Rust?

是的——虽然不是像您展示的那样一次拍摄。让我们回顾一下您的理论签名:

impl<T, E> Result<T, E> {
    fn map_unwrap<F, U, D>(&self, op: F) -> Result<U, D>
    where
        F: FnOnce(T) -> Result<U, D>,
    {}
}

这行不通 - 假设我们从 Err 开始变体 - 此代码如何知道如何从 E 转换至 D ?此外,&self不适用于想要转换类型的函数;那些通常需要 self .

您需要组合两个组件:

  1. Result::and_then

    impl<T, E> Result<T, E> {
        fn and_then<U, F>(self, op: F) -> Result<U, E>
        where
            F: FnOnce(T) -> Result<U, E>,
        {}
    }
    
  2. Result::map_err

    impl<T, E> Result<T, E> {
        fn map_err<F, O>(self, op: O) -> Result<T, F>
        where
            O: FnOnce(E) -> F,
        {}
    }
    

那么您将需要一个可以表示两种错误类型的类型。我会偷懒并使用 Box<Error>

结合在一起,你需要这样的东西:

use std::env;
use std::fs::File;
use std::error::Error;

fn main() {
    let conf = env::var("CONF")
        .map_err(|e| Box::new(e) as Box<Error>)
        .and_then(|f| File::open(f).map_err(|e| Box::new(e) as Box<Error>));
}

现在每次调用都将错误值转换为共享类型,结果可与 and_then 链接.据推测,你的真实代码会创建一个适合你的问题的错误类型,然后你会在 map_err 中使用它。称呼。我会 implement From , 那么你就可以:

let conf: Result<_, Box<Error>> = env::var("CONF")
    .map_err(Into::into)
    .and_then(|f| File::open(f).map_err(Into::into));

关于rust - 有没有办法链接结果映射和展开?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41128816/

相关文章:

sorting - 为什么这种部分快速排序实现比标准库排序慢得多?

module - 存在 main.rs 和 lib.rs 时的 Rust 模块困惑

rust - FFI 函数可以修改未声明为可变的变量吗?

regex - 如何使正则表达式宏工作?

rust - 我如何使用 Rust 将匹配的值分配为结果?

macros - Rust 宏可以创建编译时字符串吗?

rust - 为什么 `cargo build` 不显示我代码中的所有错误?

rust - 提取在 Rust 中创建实例的函数

rust - 使用运行时创建的实例的首选方式是什么?

string - 为什么从标准输入读取用户输入时我的字符串不匹配?