如何在 Rust 中复制而不是借用 i64 到闭包中?

msr*_*rd0 5 copy rust borrowing

我的代码有以下最小示例:

fn main()
{
    let names : Vec<Vec<String>> = vec![
        vec!["Foo1".to_string(), "Foo2".to_string()],
        vec!["Bar1".to_string(), "Bar2".to_string()]
    ];
    let ids : Vec<i64> = vec![10, 20];

    names.iter().enumerate().flat_map(|(i,v)| {
        let id : i64 = ids[i];
        v.iter().map(|n| 
            (n.clone(), id)
        )
    });
}
Run Code Online (Sandbox Code Playgroud)

现在,当我编译它时,rustc我收到以下错误消息:

error[E0597]: `id` does not live long enough
  --> main.rs:12:16
   |
11 |         v.iter().map(|n| 
   |                      --- capture occurs here
12 |             (n.clone(), id)
   |                         ^^ borrowed value does not live long enough
13 |         )
14 |     });
   |     -- borrowed value needs to live until here
   |     |
   |     borrowed value only lives until here
Run Code Online (Sandbox Code Playgroud)

但根据我的理解,id是类型i64,因此应该能够复制到捕获中,这正是我所需要的?

我也尝试过内联id变量但无济于事:

error[E0597]: `i` does not live long enough
  --> main.rs:11:21
   |
10 |             v.iter().map(|n| 
   |                          --- capture occurs here
11 |                 (n.clone(), ids[i])
   |                                 ^ borrowed value does not live long enough
12 |             )
13 |         });
   |         -- borrowed value needs to live until here
   |         |
   |         borrowed value only lives until here
Run Code Online (Sandbox Code Playgroud)

那么如何将我的整数复制到闭包中而不是借用它呢?

我尝试使用move,但rustc也不喜欢这样:

error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
  --> main.rs:10:17
   |
7  |         let ids : Vec<i64> = vec![10, 20];
   |             --- captured outer variable
...
10 |             v.iter().map(move |n| 
   |                          ^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
Run Code Online (Sandbox Code Playgroud)

所以我需要以某种方式rustc只移动/复制一些变量而不是其他变量?

Fre*_*ios 4

当您在 Rust 中创建闭包时,它会通过值或引用捕获变量。两者混合是不可能的。默认情况下,它通过引用捕获,但使用move关键字时,它通过值捕获(即,它在闭包内移动捕获的变量)。

因此,在您的第一个代码中,您需要id在闭包内移动:

fn main() {
    let names: Vec<Vec<String>> = vec![
        vec!["Foo1".to_string(), "Foo2".to_string()],
        vec!["Bar1".to_string(), "Bar2".to_string()],
    ];
    let ids: Vec<i64> = vec![10, 20];

    names.iter().enumerate().flat_map(|(i, v)| {
        let id: i64 = ids[i];
        v.iter().map(move |n| (n.clone(), id))
    });
}
Run Code Online (Sandbox Code Playgroud)

然后你问是否可以“内联” ids

fn main() {
    let names: Vec<Vec<String>> = vec![
        vec!["Foo1".to_string(), "Foo2".to_string()],
        vec!["Bar1".to_string(), "Bar2".to_string()],
    ];
    let ids: Vec<i64> = vec![10, 20];

    names.iter().enumerate().flat_map(|(i, v)| {
        v.iter().map(|n| (n.clone(), ids[i]))
    });
}
Run Code Online (Sandbox Code Playgroud)

您根本无法放入ids内部闭包中,因为您已经位于FnMut闭包内(需要独占访问)。因此,您无法借用或移动,ids因为它已经被FnMut关闭借用了。最小复制:

fn main() {
    let mut i = 0;

    let mut closure = || {
        i = 2;
        || {
            println!("i = {}", i);
        }
    };

    closure()();
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为你的最后一段不准确。你*可以*在内部闭包中借用`ids`,但`i`不能被借用(因为它属于外部闭包)。另一方面,你可以*移动*`i`(因为它是`Copy`),但你不能移动`ids`,因为外部闭包只借用它。您需要在移动“i”时借用“ids”,您可以通过[在外部闭包中引用“ids”并使用“move”移动两者来实现](https://play.rust-lang .org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=196fe9c95c7abce220619c846ce7ed8e) (2认同)
  • *两者的混合是不可能的* - 这在技术上是准确的,但正如 trentcl 所示,您可以采用显式引用,然后将引用移入,有效地获得混合。 (2认同)