【发布时间】:2020-05-04 22:46:32
【问题描述】:
我有以下功能:
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))
})
}
但是,这很难写。我从一些更简单但不起作用的东西开始,但我不明白为什么它不起作用。
-
这是我的第一个版本:
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 -
我认为我可能需要
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,我想这是有道理的,但我不知道如何解决它。 -
出于绝望,我尝试了以下方法:
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>| { | ^^^^^^^^^^^^^^^^^^^^^^^我猜,所有权的问题是有道理的。这就是让我找到上述实际可行的解决方案的原因。
-
我尝试过的另一件事无效:
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_1 和map_option_3 是如何失败的,因为move 没有被用来明确移动所有权,但我很惊讶map_option_2 和map_option_4 失败了。
我非常很惊讶map_option_2 不起作用,但实际的map_option 功能起作用。对我来说,这些实际上是相同的功能。
为什么每个map_option_X 函数都无法编译??
【问题讨论】:
-
我还收到类似于以下内容的警告:
trait objects without an explicitdyn` 已弃用. It recommends using types likeBoxB>` 而不是 Box<Fn(A) -> B>。我实际上并没有检查这是否相关。 -
dyn的存在与否不会改变程序的语义。 -
我应该补充一点,这个问题的灵感来自以下 Codewars 问题:codewars.com/kata/5922543bf9c15705d0000020/rust
标签: function lambda rust move-semantics lifetime