【问题标题】:Why is the value moved into the closure here rather than borrowed?为什么这里的值被移动到闭包中而不是借来的?
【发布时间】:2016-08-12 08:34:09
【问题描述】:

Rust Book 的Error Handling chapter 包含一个关于如何使用OptionResult 组合子的示例。读取文件并通过应用一系列组合器将内容解析为i32 并在Result<i32, String> 中返回。 现在,当我查看代码时,我感到很困惑。在那里,在一个 and_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&lt;usize&gt; 返回值Read::read_to_string。 问题:我认为 notmove 标记关闭会默认借用任何引用的值,这会导致借用检查器抱怨contents 的寿命不够长。但是,这段代码编译得很好。这意味着,Stringcontents 被移入并随后移出闭包。为什么在没有明确的move 的情况下这样做?

【问题讨论】:

    标签: closures rust


    【解决方案1】:

    我认为 not 用 move 标记闭包会默认借用任何引用的值,

    不完全是。编译器对闭包体内的代码进行一些检查,并跟踪封闭变量的使用情况。

    当编译器看到对变量调用了方法时,它会查看接收者是什么类型(self&amp;self&amp;mut self)。当变量用作参数时,编译器还会跟踪它是按值、引用还是可变引用。最严格的要求将是默认使用的。

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

    在这种情况下,变量是从闭包中返回的,这一定意味着它是按值使用的。因此变量会自动移动到闭包中。


    偶尔move 关键字太大了,因为它将所有引用的变量移入。有时您可能只想强制一个变量搬进来了,但其他人没有。在这种情况下,我所知道的最佳解决方案是明确引用并将引用移入:

    fn main() {
        let a = 1;
        let b = 2;
    
        {
            let b = &b;
            needs_to_own_a(move || a_function(a, b));
        }
    }
    

    【讨论】:

    • map 的闭包被传递了一个 usize 作为参数,它返回一个字符串。因此 String 值被移出闭包环境,因此必须首先将其移入。这基本上就是这里编译器的推理吗?
    • @JonasTepe 听起来很正确——如果它被用于闭包内的某些函数/方法调用的值,它也会被移入。
    猜你喜欢
    • 1970-01-01
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 2015-06-05
    • 2015-02-26
    • 1970-01-01
    相关资源
    最近更新 更多