I want to store a callback that can take different types of parameters (both owned values and references), and can also modify its environment (hence the FnMut). When invoking the callback with a reference, I'd like the compiler to enforce that the parameter is only valid in the closure body. I've tried to implement this using boxed closures.
A minimum example shown below:
fn main() {
let mut caller = Caller::new();
let callback = |x: &Foo| println!("{:?}", x);
caller.register(callback);
let foo = Foo{
bar: 1,
baz: 2,
};
//callback(&foo); // works
caller.invoke(&foo); // borrowed value does not live long enough
}
struct Caller<'a, T> {
callback: Box<dyn FnMut(T) + 'a>
}
impl<'a, T> Caller<'a, T> {
fn new() -> Self {
Caller {
callback: Box::new(|_| ()),
}
}
fn register(&mut self, cb: impl FnMut(T) + 'a) {
self.callback = Box::new(cb);
}
fn invoke(&mut self, x: T) {
(self.callback)(x);
}
}
#[derive(Debug, Clone)]
struct Foo {
bar: i32,
baz: i32,
}
I want to understand why this works if I directly call callback()
but the compiler complains about lifetimes if I invoke it through a struct than owns the closure. Perhaps it has something to do with the Box
? I can get this to work if I define foo
before caller
, but I'd like to avoid this.