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

无聊

我有以下功能:

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
    

这是一个具有上述所有功能游乐场


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

我有点了解map_option_1map_option_3失败,因为move没有使用显式移动所有权,但我很奇怪map_option_2map_option_4失败。

惊讶的是map_option_2不行的,但实际map_option功能如何工作。对我来说,这些功能实际上是相同的。

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

弗朗西斯·加涅

我以为我可能需要move关闭,以便它拥有所有权a2b

没错,您确实需要move外部封闭。没有move,闭包将a2b通过引用捕获但是,a2b是一个局部参数,并且返回引用了局部变量的闭包是无效的。

添加move到内部闭包会导致错误,因为该函数返回Fn闭包。对于此参数,让我们考虑以下map_option_5函数:

pub fn map_option_5<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(move |a| a2b(a))
    })
}

如果内部闭包a2b按值捕获,而外部闭包也是move闭包,则两个闭包最终都将按a2b捕获根据所有权规则,一次只能有一个封闭a2b,因此,在调用外部封闭时,它会a2b移出自身(破坏外部封闭)并进入内部封闭(仅对于FnOnce封闭而言,因为他们需要self,而不是&mut self&self)。出现错误消息的原因是我们返回的是Fn闭包,而不是FnOnce闭包。我们确实可以通过返回一个FnOnce闭包来解决此问题(但是不能多次调用它):

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

现在,让我们讨论一下为什么map_option作品,而map_option_2不会。问题源于Option::map拥有闭包参数所有权的事实因此,我们最终陷入与map_option_5上述类似的情况Option::map需要一个FnOnce,因为它最多只需要调用一次。不过,将其更改a2b为aBox<FnOnce(A) -> B>并没有帮助,因为实际上它可以在对的许多调用中使用map

有一种避免内部闭包的方法:将传递a2bmap这行得通,因为

  1. Box<F> where F: Fn<A>实施Fn<A>
  2. &F where F: Fn<A>实现FnOnce<A>(以及Fn<A>,尽管此处无关紧要)。
pub fn map_option_2a<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)
    })
}

闭包仍然拥有的所有权a2b,但在调用时不会消耗它,因此可以多次调用该闭包。

map_option之所以有效,是因为它的外层封闭不需要消耗a2b内盖a2b通过引用从外盖捕获之所以可行,是Fn因为调用闭包只需要共享引用即可。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何将变量移出闭包?

来自分类Dev

为什么我不能在闭包中访问局部变量

来自分类Dev

为什么Swift闭包变量类型不能隐式展开为可选?

来自分类Dev

Groovy:为什么闭包本身不能访问?

来自分类Dev

为什么不能修改内联方法的闭包参数?

来自分类Dev

不能在闭包内移出借来的内容

来自分类Dev

为什么不能将Gremlin GraphTraversal捕获为Groovy变量?

来自分类Dev

为什么不能将python的print分配给变量?

来自分类Dev

为什么不能将“宽”用作变量名?

来自分类Dev

JavaScript-为什么我不能将变量称为“名称”?

来自分类Dev

为什么不能将这两个变量相除?

来自分类Dev

为什么不能将cin转换为自动声明的变量?

来自分类Dev

JavaScript-为什么我不能将变量称为“名称”?

来自分类Dev

为什么我不能将插值变量用作varname?

来自分类Dev

为什么我不能将 require 函数的参数用作变量

来自分类Dev

为什么Python无法在闭包中增加变量?

来自分类Dev

为什么在闭包 Laravel 中未定义变量?

来自分类Dev

无法从`Fn`闭包中移出捕获的外部变量

来自分类Dev

为什么“ for .. in”允许闭包?

来自分类Dev

为什么“ for .. in”允许闭包?

来自分类Dev

为什么不能将变量用作设置环境变量的命令的前缀?

来自分类Dev

为什么不能将变量用作设置环境变量的命令的前缀?

来自分类Dev

在Scheme或STk中,功能将显示为过程或闭包,但是LISP为什么会给出错误?

来自分类Dev

为什么这种闭包不能在int范围的每个元素上执行?

来自分类Dev

为什么我的闭包内部的函数的效果不能持久存在?

来自分类Dev

为什么我不能访问原型函数(使用闭包)?

来自分类Dev

为什么不能将错误归类?

来自分类Dev

为什么不能将哈希值相乘?

来自分类Dev

为什么不能将方法引用直接分配给Object类型的变量?

Related 相关文章

  1. 1

    如何将变量移出闭包?

  2. 2

    为什么我不能在闭包中访问局部变量

  3. 3

    为什么Swift闭包变量类型不能隐式展开为可选?

  4. 4

    Groovy:为什么闭包本身不能访问?

  5. 5

    为什么不能修改内联方法的闭包参数?

  6. 6

    不能在闭包内移出借来的内容

  7. 7

    为什么不能将Gremlin GraphTraversal捕获为Groovy变量?

  8. 8

    为什么不能将python的print分配给变量?

  9. 9

    为什么不能将“宽”用作变量名?

  10. 10

    JavaScript-为什么我不能将变量称为“名称”?

  11. 11

    为什么不能将这两个变量相除?

  12. 12

    为什么不能将cin转换为自动声明的变量?

  13. 13

    JavaScript-为什么我不能将变量称为“名称”?

  14. 14

    为什么我不能将插值变量用作varname?

  15. 15

    为什么我不能将 require 函数的参数用作变量

  16. 16

    为什么Python无法在闭包中增加变量?

  17. 17

    为什么在闭包 Laravel 中未定义变量?

  18. 18

    无法从`Fn`闭包中移出捕获的外部变量

  19. 19

    为什么“ for .. in”允许闭包?

  20. 20

    为什么“ for .. in”允许闭包?

  21. 21

    为什么不能将变量用作设置环境变量的命令的前缀?

  22. 22

    为什么不能将变量用作设置环境变量的命令的前缀?

  23. 23

    在Scheme或STk中,功能将显示为过程或闭包,但是LISP为什么会给出错误?

  24. 24

    为什么这种闭包不能在int范围的每个元素上执行?

  25. 25

    为什么我的闭包内部的函数的效果不能持久存在?

  26. 26

    为什么我不能访问原型函数(使用闭包)?

  27. 27

    为什么不能将错误归类?

  28. 28

    为什么不能将哈希值相乘?

  29. 29

    为什么不能将方法引用直接分配给Object类型的变量?

热门标签

归档