我有一个结构体,它包含一个函数向量和一个迭代每个函数并调用它的方法。
struct App {
functions: Vec<Box<dyn FnOnce(i32) -> i32>>
}
impl App {
pub fn run(&mut self) {
for function in &mut self.functions {
println!("{}", (function)(1));
}
}
}
然而,我移动了向量,我还没有找到一个干净的方法来复制它。
cannot move out of `*function` which is behind a mutable reference
move occurs because `*function` has type `Box<dyn FnOnce(i32) -> i32>`, which does not
implement the `Copy` trait (rustc E0507)
那么,有没有办法调用函数而不移动它,或者有没有一种干净的方法来复制它呢?
1条答案
按热度按时间yh2wf1be1#
Rust中函数特性的构造方式在开始时有点混乱,但遵循相同的所有权模式。
有三种功能所有权类型:
FnOnce
-类似于self
。要求调用方拥有此函数对象,并且将使用此对象。这是调用方对函数所能做出的最强保证,并且每个函数都是FnOnce
。FnMut
-类似于&mut self
。要求调用方持有对函数的可变引用。可以多次调用。所有可能有副作用的函数至少需要FnMut
所有权。每个可以通过FnMut
执行的函数也与FnOnce
兼容,因为FnOnce
具有更强的所有权保证。Fn
-类似于&self
。允许调用者不可变地引用此对象,这意味着可以同时从多个点引用和调用此对象(重要:这里不谈多线程,多线程还需要Sync
).这是所有权要求最弱的一个,允许所有者通过这个调用的函数通常没有副作用,只是从一个输入计算一个输出.所有允许通过Fn
自动调用的函数也都可以通过FnOnce
和FnMut
调用.因为这能提供更强的所有权保障。如果不考虑这个问题,在您的例子中,您的函数是
FnOnce
,这意味着它们需要拥有,调用它们将消耗它们,特别是最后一部分,这是您在这里得到错误的原因。你在
run
方法中拥有self
的方式太弱了。你不能在你不拥有的self
对象上调用需要拥有权的FnOnce
。&mut self
对象只允许你调用FnMut
成员。因此,有两种方法可以修复代码:
self
参数的类型改为owned,但是要注意,这会使run
成为一个消耗函数,最终会破坏self
。FnMut
,当然只有当函数允许通过FnMut
调用时才可以这样做。以下是将
FnOnce
更改为Fn
后的外观示例:注意,这里的闭包
|x| 2 * x
与Fn
兼容,因为它没有任何副作用,这意味着self
变量现在可以是一个不可变的引用,因为调用这些函数可以保证不改变self
。我们还可以多次调用
app.run()
,app
不必是可变的。下面是一个需要
FnMut
的函数示例:一个二个一个一个
这个函数现在有一个副作用--每次调用它都会改变
sum
的值,因此它不再与Fn
兼容,在前面的代码中使用它会导致错误。我们的函数对象现在必须是
FnMut
,我们的self
必须变成&mut self
,我们的app
对象必须是可变的。但是,我们仍然能够多次调用
app.run()
。现在,让我们看看使用
FnOnce
的必要条件:这个闭包是
FnOnce
的原因是因为drop
,它在被调用时会破坏s
变量,并且由于显而易见的原因,这种情况只会发生一次。因此,要将其存储到
App
中,App
必须将其函数对象类型更改为FnOnce
,而且,run()
方法中的self
现在也需要作为拥有对象,因为在此过程中会破坏它的一部分。这意味着我们只能调用
app.run()
一次,也不需要把app
标记为mut
,因为它在这个过程中不会发生变异,它会被完全消耗掉,所以我们不需要担心变异性,它在之后就不能被访问了。我们现在只能调用
app.run()
一次是有意义的,因为它包含的函数也只能调用一次。我希望这能帮助你更好地理解你的处境。