为什么不能将变量移出闭包?

问题描述 投票:1回答:1

我具有以下功能:

pub fn map_option<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
    Box::new(move |opt_a: Option<A>| {
        opt_a.map(|a| a2b(a))
    })
}

但是,这很难写。我从简单的东西开始就行了,但是我不明白为什么它不行。

  1. 这是我的第一个版本:

    pub fn map_option_1<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
        Box::new(|opt_a: Option<A>| {
            opt_a.map(a2b)
        })
    }
    

    这给了我以下错误:

    error[E0507]: cannot move out of `a2b`, a captured variable in an `Fn` closure
      --> src/lib.rs:11:19
       |
    9  | pub fn map_option_1<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
       |                                              --- captured outer variable
    10 |     Box::new(|opt_a: Option<A>| {
    11 |         opt_a.map(a2b)
       |                   ^^^ move occurs because `a2b` has type `std::boxed::Box<dyn std::ops::Fn(A) -> B>`, which does not implement the `Copy` trait
    
  2. 我认为我可能需要move闭包,以便它获得a2b的所有权:

    pub fn map_option_2<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
        Box::new(move |opt_a: Option<A>| {
            opt_a.map(a2b)
        })
    }
    

    但是,这也不起作用。它失败,并显示以下消息:

    error[E0507]: cannot move out of `a2b`, a captured variable in an `Fn` closure
      --> src/lib.rs:17:19
       |
    15 | pub fn map_option_2<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
       |                                              --- captured outer variable
    16 |     Box::new(move |opt_a: Option<A>| {
    17 |         opt_a.map(a2b)
       |                   ^^^ move occurs because `a2b` has type `std::boxed::Box<dyn std::ops::Fn(A) -> B>`, which does not implement the `Copy` trait
    

    此错误消息说a2b没有实现Copy,我想这很有意义,但是我不知道如何解决它。

  3. 出于绝望,我尝试了以下操作:

    pub fn map_option_3<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
        Box::new(|opt_a: Option<A>| {
            opt_a.map(|a| a2b(a))
        })
    }
    

    这至少给了我一个不同的错误:

    error[E0373]: closure may outlive the current function, but it borrows `a2b`, which is owned by the current function
      --> src/lib.rs:22:14
       |
    22 |     Box::new(|opt_a: Option<A>| {
       |              ^^^^^^^^^^^^^^^^^^ may outlive borrowed value `a2b`
    23 |         opt_a.map(|a| a2b(a))
       |                       --- `a2b` is borrowed here
       |
    note: closure is returned here
      --> src/lib.rs:22:5
       |
    22 | /     Box::new(|opt_a: Option<A>| {
    23 | |         opt_a.map(|a| a2b(a))
    24 | |     })
       | |______^
    help: to force the closure to take ownership of `a2b` (and any other referenced variables), use the `move` keyword
       |
    22 |     Box::new(move |opt_a: Option<A>| {
       |              ^^^^^^^^^^^^^^^^^^^^^^^
    

    我猜,所有权问题很有意义。这就是导致我找到上述切实可行的解决方案的原因。

  4. 我尝试过的另一件事无效:

    pub fn map_option_4<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
        Box::new(|opt_a: Option<A>| {
            opt_a.map(move |a| a2b(a))
        })
    }
    

    这给了我以下错误:

    error[E0507]: cannot move out of `a2b`, a captured variable in an `Fn` closure
      --> src/lib.rs:29:19
       |
    27 | pub fn map_option_4<A: 'static, B: 'static> (a2b: Box<Fn(A) -> B>) -> Box<Fn(Option<A>) -> Option<B>> {
       |                                              --- captured outer variable
    28 |     Box::new(|opt_a: Option<A>| {
    29 |         opt_a.map(move |a| a2b(a))
       |                   ^^^^^^^^ ---
       |                   |        |
       |                   |        move occurs because `a2b` has type `std::boxed::Box<dyn std::ops::Fn(A) -> B>`, which does not implement the `Copy` trait
       |                   |        move occurs due to use in closure
       |                   move out of `a2b` occurs here
    

这里是每个功能的playground


我认为我对生存期和所有权没有足够的了解,以了解为什么每个功能都会失败。

[我可以理解map_option_1map_option_3如何失败,因为没有使用move显式移动所有权,但是map_option_2map_option_4失败令我感到惊讶。

非常惊讶于map_option_2不起作用,但是实际的map_option函数起作用。对我来说,这些功能实际上是相同的。

为什么每个map_option_X函数都无法编译 ??]

function lambda rust move-semantics lifetime
1个回答
1
投票

我认为我可能需要move闭包,以便获得a2b的所有权

© www.soinside.com 2019 - 2024. All rights reserved.