是否可以返回存储在self中的闭包?

时间:2018-04-21 09:58:55

标签: rust

我正在使用特征来实现像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

1 个答案:

答案 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
}

但这也需要改变特性。