Error handling 当使用带有易出错映射函数的filter_map时,如何在错误上聚合迭代器?

Error handling 当使用带有易出错映射函数的filter_map时,如何在错误上聚合迭代器?,error-handling,rust,iterator,Error Handling,Rust,Iterator,假设我想读取目录中的所有文件。我可以这样定义一个函数: use std::error::Error; use std::fs; use std::io; type Result<T> = std::result::Result<T, Box<dyn Error>>; fn read_entry(entry: io::Result<fs::DirEntry>) -> Result<Option<String>> {

假设我想读取目录中的所有文件。我可以这样定义一个函数:

use std::error::Error;
use std::fs;
use std::io;

type Result<T> = std::result::Result<T, Box<dyn Error>>;

fn read_entry(entry: io::Result<fs::DirEntry>) -> Result<Option<String>> {
    let entry = entry?;
    if entry.file_type()?.is_file() {
        Ok(Some(fs::read_to_string(entry.file_name())?))
    } else {
        Ok(None)
    }
}
使用std::error::error;
使用std::fs;
使用std::io;
类型Result=std::Result::Result;
fn read_条目(条目:io::Result)->Result{
让进入=进入?;
如果entry.file_type()?.is_file(){
Ok(一些(fs::read_to_string(entry.file_name())?)
}否则{
Ok(无)
}
}
然后试着用它

use std::path::Path;

fn read_all(dir: &Path) -> Result<Vec<String>> {
    Ok(fs::read_dir(dir)?
        .filter_map(|entry| read_entry(entry).unwrap())
        .collect())
}
使用std::path::path;
fn read_all(目录:&路径)->结果{
好的(fs::读取目录(dir)?
.filter_map(| entry | read_entry(entry).unwrap())
.collect())
}
这可以编译,但它只是
unwrap()
s错误
collect()
通常可以在错误上聚合迭代器,但我不太明白如何使用
filter\u map()
实现这一点。我怎样才能解决这个问题

对于
Iter
(这是
Iterator::collect
的一个基本特征),迭代器中有一个很好的
FromIterator
,因此它可以工作:

fn读取所有(目录和路径)->结果{
读目录(dir)?
.filter_map(| entry | read_entry(entry).transpose())
.collect()
}
对于
Iter
(这是
Iterator::collect
的一个基本特征),有一个很好的
from Iterator
,因此它可以工作:

fn读取所有(目录和路径)->结果{
读目录(dir)?
.filter_map(| entry | read_entry(entry).transpose())
.collect()
}

而不是返回
结果
您需要
选项
,即在:

  • Ok(Some(T))
    :这是一个文件,我们成功地读取了它
  • 确定(无)
    :它不是一个文件,但我们没有发现任何错误
  • Err
    :发生错误
之后:

  • Some(Ok(T))
    :这是一个文件,我们成功地读取了它
  • None
    :它不是一个文件,但我们没有发现任何错误
  • Some(Err)
    :发生了一个错误
您可以更改原始实现,但这意味着您不能使用
运算符,这很糟糕


一个更好的解决方案——正如@Kitsu所指出的那样,使用内置函数将
结果
转换为
选项
,而不是返回
结果
,即,在:

  • Ok(Some(T))
    :这是一个文件,我们成功地读取了它
  • 确定(无)
    :它不是一个文件,但我们没有发现任何错误
  • Err
    :发生错误
之后:

  • Some(Ok(T))
    :这是一个文件,我们成功地读取了它
  • None
    :它不是一个文件,但我们没有发现任何错误
  • Some(Err)
    :发生了一个错误
您可以更改原始实现,但这意味着您不能使用
运算符,这很糟糕


一个更好的解决方案——正如@Kitsu所指出的那样,使用内置函数将
结果
转换为
选项
只是为了完成,而
读取条目
失败的原因是因为使用了
条目.file\u name()
而不是
条目.path()

因此:

Ok(Some(fs::read_to_string(entry.file_name())?))
应该是:

Ok(Some(fs::read_to_string(entry.path())?))

仅为完成起见,
read\u条目
失败的原因是使用了
entry.file\u name()
而不是
entry.path()

因此:

Ok(Some(fs::read_to_string(entry.file_name())?))
应该是:

Ok(Some(fs::read_to_string(entry.path())?))

这回答了你的问题吗?不,我不想忽略错误。这回答了你的问题吗?不。我不想忽略错误。Aha
transpose()
是丢失的链接!谢谢啊哈
transpose()
是丢失的链接!谢谢同意,而且我甚至会将
read\u entry
参数更改为
entry:fs::DirEntry
,这样就可以在不使用额外闭包的情况下使用它,即
.filter\u map(read\u entry)
read\u dir()
返回
结果
s..上的迭代器?同意,而且我甚至会将
read\u entry
参数更改为
entry:fs::DirEntry
,这样就可以在不使用额外闭包的情况下使用它,即
.filter\u map(read\u entry)
read\u dir()
返回
结果
s..上的迭代器?