Reputation: 10510
I'm using a trait to implement something like the template method pattern. During parts of the algorithm execution, I'd like it to be able to invoke a callback to report its progress. The way I've been trying to make this work is by storing a Fn()
on my structs that implement the trait, and then providing a get_callback
method to provide the callbacks to the default methods on the trait. Unfortunately it's not working.
I suspect the solution will involve some combination of putting the callback in a Box
and possibly returning a reference, but I haven't been able to get it to work. Here's a minimal non-working example:
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
Upvotes: 3
Views: 97
Reputation: 30001
There is nothing special about the closure here. Your problem is this:
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
}
A simple solution would be to clone the closure instead:
impl<T: Fn() + Clone> MyTrait<T> for MyStruct<T> {
fn get_callback(&self) -> T {
self.callback.clone()
}
}
Cloning closures is only stable as of Rust 1.26 (see playground example).
Another solution would be to actually move out:
impl<T: Fn()> MyTrait<T> for MyStruct<T> {
fn get_callback(self) -> T {
// ^ no reference
self.callback
}
}
This works on stable but requires a few other changes and modifying the trait.
But most likely, the solution you want is to return a reference to the closure:
fn get_callback(&self) -> &T {
&self.callback
// ^ there
}
But this also requires to change the trait.
Upvotes: 6