问题描述
我正在尝试编写一个将glob的输出Result<Paths,PatternError>
转换为Result<Vec<PathBuf>,Error>
的函数。我有自己的Error
类型,它同时为From
和glob::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的最终工作代码