File 筛选使用fs::read_dir()发现的文件或目录

File 筛选使用fs::read_dir()发现的文件或目录,file,rust,iteration,mapping,filtering,File,Rust,Iteration,Mapping,Filtering,我有这个函数: fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> { fs::read_dir(dir)? .into_iter() .map(|x| x.map(|entry| entry.path())) .collect() } 测试输出显示目录和文件,正如它应该显示的那样。我想不出在哪里对文件/目录进行过滤。我不明白为什么映射内

我有这个函数:

fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    fs::read_dir(dir)?
        .into_iter()
        .map(|x| x.map(|entry| entry.path()))
        .collect()
}
测试输出显示目录和文件,正如它应该显示的那样。我想不出在哪里对文件/目录进行过滤。我不明白为什么映射内部的映射:它不只是一个简单的路径列表吗?这个表达式中到底发生了什么

UPD:

fn文件夹(目录:&Path)->结果{
读目录(dir)?
.into_iter()
.map(| x | x.map(| entry | entry.path()))
.filter(|x |{x.as_ref().map(| entry | entry);true})
.collect()
}

插入了一个普通筛选器(始终
true
)。它至少正在编译,但我仍然看不出应该如何使用
entry
进行文件/目录检查。对不起:)

让我们一步一步地走过这条链条

fs::read_dir(dir)?
创建目录的读取句柄,如果发生
错误
情况,则立即传播;如果没有,则
展开
成功(这是
操作符)

将此读取句柄转换为
Result

如果结果是实际的
DirEntry
,则对迭代器的每个元素调用
path()
方法。因为迭代器元素是
Result
,而不仅仅是
DirEntry
,所以第二个
map()
允许您干净地处理这个问题。剩下的是在输出上看到的路径

.collect()
将此迭代器转换回由类型提示定义的结构(此处为向量)

过滤部分可以在调用
map()
之前或之后实现,以将条目转换为
PathBuf
。如果需要基于元素本身而不是
PathBuf
进行筛选,请在它之前进行筛选。如果可以基于
路径buf
进行筛选,请在其之后进行筛选

filter()
combinator函数的使用非常简单,只要给它一个闭包,它就会将它应用于每个元素。如果闭包返回值为
true
,则保留该元素。如果为false,则删除该元素

以下是仅返回目录的示例:

fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    Ok(fs::read_dir(dir)?
        .into_iter()
        .filter(|r| r.is_ok()) // Get rid of Err variants for Result<DirEntry>
        .map(|r| r.unwrap().path()) // This is safe, since we only have the Ok variants
        .filter(|r| r.is_dir()) // Filter out non-folders
        .collect())
}
fn文件夹(目录:&Path)->结果{
好的(fs::读取目录(dir)?
.into_iter()
.filter(| r | r.is_ok())//去除结果的错误变量
.map(| r | r.unwrap().path())//这是安全的,因为我们只有Ok变量
.filter(| r | r.is_dir())//筛选出非文件夹
.collect())
}

您可以合并2个筛选器调用,并保留read\u dir的结果。deref能够检查路径是否为dir,而不使用结果

fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    fs::read_dir(dir)?
        .map(|r| r.map(|d| d.path()))
        .filter(|r| r.is_ok() && r.as_deref().unwrap().is_dir())
        .collect()
}
fn文件夹(目录:&Path)->结果{
读目录(dir)?
.map(| r | r.map(| d | d.path()))
.filter(| r | r.is_ok()&&r.as_deref().unwrap().is_dir())
.collect()
}
您还可以将“过滤器和贴图”与“过滤器和贴图”结合使用,并使用“确定()”和“然后()取消展开”

fn文件夹(目录:&Path)->结果{
好的(fs::读取目录(dir)?
.filter|u map(|e|{
e、 好的,然后呢{
设p=d.path();
如果p.is_dir(){
一些(p)
}否则{
没有一个
}
})
})
.collect())
}

您可能希望添加一行,大意是
read_dir
返回一个
迭代器,它解释了内部
x.map
…为什么不
。map(|entry | entry.path())
?@AlexeyOrlov
read_dir
提供结果迭代器。“如果不处理结果,就不能使用结果的内部值。”阿列克谢奥尔洛夫·Jmb回答了你的问题,他是对的。我将编辑答案以添加此详细信息我仍然不太明白。一个映射,一个过滤器,不管懒惰与否,都会作用于一系列对象。地图在什么序列上工作?在我看来,内部映射在
结果
上起作用,这是没有顺序的。如果您还没有阅读,中的文档可能对您很有帮助。您想做什么样的筛选?只传递文件,还是只传递目录。
.map(|x|
  x.map(|entry| entry.path())
)
.collect()
fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    Ok(fs::read_dir(dir)?
        .into_iter()
        .filter(|r| r.is_ok()) // Get rid of Err variants for Result<DirEntry>
        .map(|r| r.unwrap().path()) // This is safe, since we only have the Ok variants
        .filter(|r| r.is_dir()) // Filter out non-folders
        .collect())
}
fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    fs::read_dir(dir)?
        .map(|r| r.map(|d| d.path()))
        .filter(|r| r.is_ok() && r.as_deref().unwrap().is_dir())
        .collect()
}
fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    Ok(fs::read_dir(dir)?
        .filter_map(|e| {
            e.ok().and_then(|d| {
                let p = d.path();
                if p.is_dir() {
                    Some(p)
                } else {
                    None
                }
            })
        })
        .collect())
}