gpt4 book ai didi

rust - Vanilla Rust中的目录遍历

转载 作者:行者123 更新时间:2023-12-03 11:42:51 29 4
gpt4 key购买 nike

我是Rust的新手,试图了解基本的目录遍历。我发现的几乎所有示例都利用了walkdirglob库,这些库我都取得了很好的成功。但是,我现在正尝试仅使用std lib来执行此操作。
标准lib文档中有一个primitive example,其中列出了以下功能:

fn visit(path: &Path, cb: &dyn Fn(&PathBuf)) -> io::Result<()> {
for e in read_dir(path)? {
let e = e?;
let path = e.path();
if path.is_dir() {
visit(&path, cb)?;
} else if path.is_file() {
cb(&path);
}
}
Ok(())
}
我很困惑的部分是如何在闭包的上下文中访问 cb函数。我很难找到一个例子。
例如,我想做一些基本的事情,例如将结果路径收集到 Vec中。显然,这不起作用:
fn main() {
// create a new path
let path = Path::new(PATH);
let mut files = Vec::new();

visit(path, |e| {
files.push(e);
});
}
我收到的错误是:
expected reference `&dyn for<'r> std::ops::Fn(&'r std::path::PathBuf)`
found closure `[closure@src/main.rs:24:17: 26:6 files:_]
所以我的问题是,如何返回 Fn并在闭包上下文中处理结果?

最佳答案

您的代码有多个问题,但是第一个收到错误消息的原因是因为&dyn Fn(&PathBuf)期望引用一个函数。您可以按照错误消息中的建议解决该错误:help: consider borrowing here: '&|e| files.push(e)'这将使您的调用变成:

visit(path, &|e| files.push(e));
但是,此代码仍然不正确,并导致另一个错误:
error[E0596]: cannot borrow `files` as mutable, as it is a captured variable in a `Fn` closure
--> playground\src\main.rs:48:22
|
48 | visit(path, &|e| files.push(e));
| ^^^^^ cannot borrow as mutable
这次是因为您要在 files(不可变闭包)中对 Fn进行突变。要解决此问题,您需要将函数类型更改为 FnMut(有关更多信息,请参见 Closures As Input Parameters):
fn visit(path: &Path, cb: &dyn FnMut(&PathBuf))
但是您仍然没有完成。现在存在另一个错误,但与第一个错误一样,它带有有关需要更改的建议:
error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference
--> playground\src\main.rs:39:13
|
32 | fn visit(path: &Path, cb: &dyn FnMut(&PathBuf)) -> io::Result<()> {
| -------------------- help: consider changing this to be a mutable reference: `&mut dyn for<'r> std::ops::FnMut(&'r std::path::PathBuf)`
...
39 | cb(&path);
| ^^ `cb` is a `&` reference, so the data it refers to cannot be borrowed as mutable
为了使闭包能够可变地借用它使用的数据,还必须对闭包本身进行可变引用,并且需要更新 visit()调用以匹配:
fn visit(path: &Path, cb: &mut dyn FnMut(&PathBuf))
...
visit(path, &mut |e| files.push(e));
几乎在那里,但是有一个最终错误要解决:
error[E0521]: borrowed data escapes outside of closure
--> playground\src\main.rs:48:26
|
47 | let mut files = Vec::new();
| --------- `files` declared here, outside of the closure body
48 | visit(path, &mut |e| files.push(e));
| - ^^^^^^^^^^^^^ `e` escapes the closure body here
| |
| `e` is a reference that is only valid in the closure body
您已将闭包定义为对 PathBuf( &PathBuf)进行引用,但是您正试图将这些引用插入闭包外部的 Vec中,这将不起作用,因为一旦闭包,这些引用将无效超出范围。相反,您应该使用一个拥有的值-只需 PathBuf即可。您还需要更新对闭包的用法,以传递 PathBuf而不是引用:
fn visit(path: &Path, cb: &mut dyn FnMut(PathBuf))
...
cb(path);
终于成功了!这是完整程序现在的样子。请注意,您还应该 unwrap()调用 visit(),因为它返回了 Result。我还添加了一个简单的 for循环以打印出文件名。
use std::path::{Path, PathBuf};
use std::fs::*;
use std::io;

fn visit(path: &Path, cb: &mut dyn FnMut(PathBuf)) -> io::Result<()> {
for e in read_dir(path)? {
let e = e?;
let path = e.path();
if path.is_dir() {
visit(&path, cb)?;
} else if path.is_file() {
cb(path);
}
}
Ok(())
}

fn main() {
let path = Path::new("./your/path/here");
let mut files = Vec::new();
visit(path, &mut |e| files.push(e)).unwrap();
for file in files {
println!("{:?}", file);
}
}

关于rust - Vanilla Rust中的目录遍历,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63542762/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com