您的代码存在多个问题,但您收到错误消息的第一个问题是因为&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
这一次,是因为您在 Fn(不可变闭包)内对 files 进行了变异。要解决此问题,您需要将函数类型更改为 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);
}
}