【问题标题】:Rust, make a closure inside a closure avoiding "closure may outlive the current function"Rust,在闭包内创建一个闭包,避免“闭包可能比当前函数寿命更长”
【发布时间】:2020-07-15 02:05:13
【问题描述】:

我正在尝试编写一个函数来转换表单中的数据结构:

input = [("a", [1,2,3]), ("b", [4,5,6])]

进入

output = [(a,1), (c,2) ..... (b,6)] 

我的代码目前是这样的:

    let foo=vec![('a', vec![1,2,3]), ('v', vec![2,3,4])];
    let baz: Vec<(char,i32)> = foo.into_iter().map(|a|a.1.into_iter().map( |b|(a.0, b))).flatten().collect();
    println!("{:?}",baz);

我收到此错误:

error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function
  --> src/lib.rs:10:76
   |
10 |     let baz: Vec<(char,i32)> = foo.into_iter().map(|a|a.1.into_iter().map( |b|(a.0, b))).flatten().collect();
   |                                                                            ^^^ - `a` is borrowed here
   |                                                                            |
   |                                                                            may outlive borrowed value `a`
   |
note: closure is returned here
  --> src/lib.rs:10:55
   |
10 |     let baz: Vec<(char,i32)> = foo.into_iter().map(|a|a.1.into_iter().map( |b|(a.0, b))).flatten().collect();
   |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword
   |
10 |     let baz: Vec<(char,i32)> = foo.into_iter().map(|a|a.1.into_iter().map( move |b|(a.0, b))).flatten().collect();
   |                                                                            ^^^^^^^^

error[E0382]: borrow of moved value: `a`
  --> src/lib.rs:10:76
   |
10 |     let baz: Vec<(char,i32)> = foo.into_iter().map(|a|a.1.into_iter().map( |b|(a.0, b))).flatten().collect();
   |                                                       ---                  ^^^ - borrow occurs due to use in closure
   |                                                       |                    |
   |                                                       value moved here     value borrowed here after partial move
   |
   = note: move occurs because `a.1` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait

我认为这意味着 Rust 不知道如何复制我的 i32s 向量,因此认为它必须改为移动 vec,但不能这样做。

我该如何解决这个问题?为 vec 实现一个 Copy 方法,还是有更好的方法来做到这一点?

【问题讨论】:

  • 我不明白你是如何从输入中得到 (c,2) 的。你的意思是说output = [(a,1), (a,2) ... (b,6)]?你的意思是“a”和“b”是单引号,就像它们在代码中一样?

标签: rust closures borrow


【解决方案1】:

IntoIterator 消耗并产生值。由于Vec 没有实现Copy,所以当你调用a.1.into_iter() 时,它会被移动。你可以这样克隆它:a.1.clone().into_iter()

另外,您想使用 move 关键字在闭包中获取 a 的所有权。

let baz: Vec<(char, i32)> = foo
    .into_iter()
    .map(|a| a.1.clone().into_iter().map(move |b| (a.0, b)))
    .flatten()
    .collect();
println!("{:?}", baz);
// [('a', 1), ('a', 2), ('a', 3), ('v', 2), ('v', 3), ('v', 4)]

【讨论】:

    【解决方案2】:

    当你调用a.1.into_iter()时,a被移动了,不能再在内闭包中借用了。

    最简单的解决方案是解构a,这样每个组件都可以单独借用/移动:

    .map(|(c, v)| v.into_iter().map(move |b| (c, b)))
    

    还要注意move 关键字,这意味着c 被移动到内部闭包中,因此它可以比外部闭包更长寿。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-02
      • 2019-11-13
      • 2018-07-17
      • 1970-01-01
      • 2022-01-14
      • 2014-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多