微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决将Result上的迭代器转换为Result <Vec <_>,_>

我正在尝试编写一个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<_>>>()?,但这没用。

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

解决方法

这里有两个问题:

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的最终工作代码

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。