在闭包中处理可变计数器变量

时间:2014-08-25 10:35:30

标签: rust

我编写了一个程序来访问基于的目录 关于此page的示例。

编译时,编译显示以下'note':

由于在关闭时使用,

此前借用file_counter;

如何显示file_counter的值?

在此程序中,是否有更好的(即更像功能)方法来计算显示的文件, 也许是一个不可变的变量和/或递归?

非常感谢。

fn main() {
    let mut file_counter = 0i;
    let display_path_closure = |path: &Path| {
            file_counter += 1;
            println!("{}) path = {}", file_counter, path.display());
        };
    let path = Path::new("z:/abc");
    let _ = match visit_dirs(&path, display_path_closure) {
        Err(e) => println!("error: {}", e),
        Ok(_) => println!("Counter: {}", file_counter)
    };
}

fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> {

    if dir.is_dir() {
        let contents = try!(fs::readdir(dir));
        for entry in contents.iter() {
            if entry.is_dir() {
                try!(visit_dirs(entry, |p| cb(p)));
             } else {
                cb(entry);
            }
        }
        Ok(())
    } else {
        Err(io::standard_error(io::InvalidInput))
    }
}

1 个答案:

答案 0 :(得分:0)

你可以通过轻微的重组来解决这个问题,将关闭置于一个内部块中:

fn main() {
    let path = Path::new("z:/abc");

    let mut file_counter = 0i;

    let result = {
        let display_path_closure = |path: &Path| {
            file_counter += 1;
            println!("{}) path = {}", file_counter, path.display());
        };
        visit_dirs(&path, display_path_closure)
    };

    let _ = match result {
        Err(e) => println!("error: {}", e),
        Ok(_) => println!("Counter: {}", file_counter)
    };
}

至于它为什么会发生,这是因为闭包通过唯一引用(在你的情况下是可变的)捕获它的所有环境,好像它被声明为这样(假装关闭时刻按值捕获它们的环境;实际上这是unboxed闭包的工作方式):

let mut file_counter = 0i;
let file_counter_ref = &mut file_counter;
// file_counter_ref is a plain pointer so it is copied into the closure,
// not taken by reference itself
let display_path_closure = |path: &Path| {
    *file_counter_ref += 1;
    println!("{}) path = {}", *file_counter_ref, path.display());
};

因此file_counter_ref引用持续到定义闭包的块的末尾。在您的情况下,它是从闭包声明开始的整个main函数。我同意,这可能是令人惊讶的,我当然也会认为闭包环境借助于闭包(例如当闭包被移入函数并且此函数返回时),但这就是现在的情况。

Rust中闭包的情况目前还不稳定:刚刚将未装箱的闭包添加到语言中,因此旧的盒装闭包(如本例中的闭包)很快就会消失;此外,借阅检查器是also being improved。这些功能可能会以复杂的方式进行交互,因此您的原始示例很快就会成为可能:)(当然只是推测)