将Result上的迭代器转换为Result <Vec <_>,_>

时间:2020-10-30 02:51:15

标签: rust

我正在尝试编写一个将glob的输出Result<Paths, PatternError>转换为Result<Vec<PathBuf>, Error>的函数。我有自己的Error类型,它同时为Fromglob::GlobError实现了glob::PatternError。目前,我已执行以下操作:

fn glob_abs_path(fpath: &str) -> Result<Vec<PathBuf>, Error> {
    Ok(glob(fpath)?.map(|val| val.unwrap()).collect::<Vec<_>>())
}

我正在寻找一种删除对val.unwrap的调用并允许在遇到GlobError时返回的方法。我尝试使用collect::<Result<Vec<_>>>()?,但这没用。

对问题标题含糊不清表示歉意。我是新手,对这个问题还不熟悉。

1 个答案:

答案 0 :(得分:0)

这里有两个问题:

fn glob_abs_path(fpath: &str) -> std::result::Result<Vec<PathBuf>, Error> {
  Ok(glob(fpath)?.map(|val| val.unwrap()).collect::<Vec<_>>())
}

glob_abs_path的末尾,您正在将值收集到Vec中。如果您尝试在vec上使用?运算符,它将失败:

error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
  --> src/lib.rs:26:8
   |
26 |     Ok(glob(fpath)?.map(|val| val.unwrap()).collect::<Vec<_>>()?)
   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied 
to type `std::vec::Vec<std::result::Result<std::path::PathBuf, glob::GlobError>>`

?运算符只能应用于实现std::ops::Try的值,即Result<_, _>。因此,我们要做的是将迭代器收集到Result中:

fn glob_abs_path(fpath: &str) -> std::result::Result<Vec<PathBuf>, Error> {
  Ok(glob(fpath)?.map(|val| val.unwrap()).collect::<std::result::Result<Vec<_>, _>>()?)
}

但是,我们在这里遇到另一个错误:

error[E0277]: a value of type `std::result::Result<std::vec::Vec<_>, _>` cannot be built 
from an iterator over elements of type `std::path::PathBuf`
  --> src/lib.rs:26:43
   |
26 |   Ok(glob(fpath)?.map(|val| val.unwrap()).collect::<std::result::Result<Vec<_>, _>>())
   |                                           ^^^^^^^ value of type 
   |  `std::result::Result<std::vec::Vec<_>, _>` cannot be built from 
   |  `std::iter::Iterator<Item=std::path::PathBuf>`
   |

这里的问题是我们在收集值.map(|val| val.unwrap())之前先对其进行了包装,并且迭代器不知道如何将未包装的值(PathBuf)转换为Result。删除取消包装的呼叫可解决此问题:

fn glob_abs_path(fpath: &str) -> std::result::Result<Vec<PathBuf>, Error> {
    Ok(glob(fpath)?.collect::<std::result::Result<Vec<_>, _>>()?)
}

现在可以编译代码。您提到您有Result的类型别名:

type MyResult<T> = std::result::Result<T, Error>

您可以在返回值中使用此类型别名:

fn glob_abs_path(fpath: &str) -> MyResult<Vec<PathBuf>> {
    Ok(glob(fpath)?.collect::<std::result::Result<Vec<_>, _>>()?)
}

但是,当您使用它来收集迭代器时:

fn glob_abs_path(fpath: &str) -> MyResult<Vec<PathBuf>> {
    Ok(glob(fpath)?.collect::<MyResult<Vec<_>>>()?)
}

失败:

error[E0277]: a value of type `std::result::Result<std::vec::Vec<_>, Error>` 
cannot be built from an iterator over elements of type `std::result::Result<std::path::PathBuf, glob::GlobError>`
  --> src/lib.rs:26:21
   |
26 |     Ok(glob(fpath)?.collect::<MyResult<Vec<_>>>()?)
   |                     ^^^^^^^ value of type `std::result::Result<std::vec::Vec<_>, Error>` 
   |  cannot be built from `std::iter::Iterator<Item=std::result::Result<std::path::PathBuf, glob::GlobError>>`
   |

这是因为MyResult明确将返回值声明为您的自定义错误类型。 Iterator无法将GlobError转换为您的Error。该转换由?运算符处理:

fn glob_abs_path(fpath: &str) -> MyResult<Vec<PathBuf>> {
  Ok(glob(fpath)?.collect::<std::result::Result<Vec<_>, GlobError>>()?)
}

从上面可以看到,迭代器被收集到<std::result::Result<Vec<_>, GlobError>中,然后由std::result::Result<Vec<_>, YourError>运算符转换为MyResult?)。

这是Rust Playground的最终工作代码