为什么这里的价值会进入收盘而不是借入?

时间:2016-08-12 08:34:09

标签: closures rust

Rust Book的Error Handling chapter包含有关如何使用OptionResult的组合器的示例。读取文件并通过应用一系列组合器将内容解析为i32并在Result<i32, String>中返回。 现在,当我查看代码时,我感到困惑。在那里,在an_then的一个闭包中创建了一个本地String值,随后作为返回值传递给另一个组合器。

以下是代码示例:

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    File::open(file_path)
         .map_err(|err| err.to_string())
         .and_then(|mut file| {
              let mut contents = String::new(); // local value
              file.read_to_string(&mut contents)
                  .map_err(|err| err.to_string())
                  .map(|_| contents) // moved without 'move'
         })
         .and_then(|contents| {
              contents.trim().parse::<i32>()
                      .map_err(|err| err.to_string())
         })
         .map(|n| 2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {}", err),
    }
}

我指的是contents。它是在应用于map std::io::Result<usize>返回值的Read::read_to_string组合器中创建并稍后引用的。 问题:我认为用move标记闭包的会默认借用任何引用的值,这会导致借用检查器抱怨,contents不会长寿足够。但是,这段代码编译得很好。这意味着,String contents被移入闭包中,并且随后被移出。为什么没有明确的move

就完成了

1 个答案:

答案 0 :(得分:3)

  

我认为标记带移动的闭包会默认借用任何引用的值,

不完全。编译器对闭包体内的代码进行了一些检查,并跟踪闭合变量的使用方式。

当编译器发现在变量上调用方法时,它会查看接收器的类型(self&self,{{1} })。当变量用作参数时,编译器还会通过值,引用或可变引用来跟踪它。无论最严格的要求是什么,默认情况下都会使用。

偶尔,这种分析还不够完整 - 即使变量仅用作参考,我们打算让闭包拥有变量。这通常发生在返回闭包或将其移交给另一个线程时。

在这种情况下,变量从闭包返回,这必然意味着它被值使用。因此变量将自动移入闭包中。

偶尔 &mut self关键字太大了,因为它会移动所有引用的变量。有时您可能只想强制一个变量被移入而不是其他人。在这种情况下,我所知道的最佳解决方案是制作一个明确的引用并移动引用:

move