我正在使用特征来实现像template method pattern这样的东西。在算法执行的部分过程中,我希望它能够调用回调来报告其进度。我一直在努力实现这项工作的方法是在实现特征的结构上存储Fn()
,然后提供get_callback
方法来为特征上的默认方法提供回调。不幸的是它没有用。
我怀疑解决方案会涉及将回调放在Box
并可能返回引用的某种组合,但我无法让它工作。这是一个最小的非工作示例:
trait MyTrait<T: Fn()> {
fn default(&self) {
let cb = self.get_callback();
cb();
}
fn get_callback(&self) -> T;
}
struct MyStruct<T: Fn()> {
callback: T,
}
impl<T: Fn()> MyTrait<T> for MyStruct<T> {
fn get_callback(&self) -> T {
self.callback
}
}
fn main() {
let x = MyStruct { callback: || {} };
x.default();
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:16:9
|
16 | self.callback
| ^^^^ cannot move out of borrowed content
答案 0 :(得分:6)
这里的封闭没有什么特别之处。你的问题是:
fn get_callback(&self) -> T {
// ^ you are borrowing self
// ^ but you are not returning a reference
self.callback
// ^ so callback needs to be moved out
}
一个简单的解决方案是克隆闭包:
impl<T: Fn() + Clone> MyTrait<T> for MyStruct<T> {
fn get_callback(&self) -> T {
self.callback.clone()
}
}
从Rust 1.26 (see playground example)开始,克隆闭包只是稳定的。
另一个解决方案是实际迁出:
impl<T: Fn()> MyTrait<T> for MyStruct<T> {
fn get_callback(self) -> T {
// ^ no reference
self.callback
}
}
此works on stable但需要进行一些其他更改并修改特征。
但最有可能的是,您想要的解决方案是return a reference to the closure:
fn get_callback(&self) -> &T {
&self.callback
// ^ there
}
但这也需要改变特性。