For background context: I am creating an Observer/Subscriber based Global Event System (using single shared event systems). I decided to use FnMut
as my callback closure. The lifetime 'a
placed at the impl
of the makeshift struct Data<'a>
should allow the callback
parameter in the method mut_func()
to live as long as the whole Data
struct. Because the callback
parameter uses the F
generic which is definitely constrained by the lifetime 'a
. But the error is still appearing stating that the callback
parameter does not live long enough.
I originally used Box<T>
as my container for the dyn FnMut(u32)
, but the Box<T>
requires the callback to be 'static
(because I am casting the boxed generic into a box trait objects) which in my scenario is not achievable (for readability). I then tried to use Rc<RefCell<T>>
which sadly does not support trait objects.
Also, I am using generics for callback
parameter because I want that function to have higher readability instead of having to see Box<T>
wrapping around an entire closure that will be everywhere, since this Event System will be my central part of my program. I will do anything to make the 'front-end' more readable and cleaner (except for significant performance impact).
Note: This is my example program. I can post the actual program if needed.
Error:
error[E0597]: `callback` does not live long enough
> | impl<'a> Data<'a> {
> | -- lifetime `'a` defined here
> | fn mut_func<F: FnMut(u32) -> () + 'a>(&mut self, mut callback: F) {
> | self.o.push(&mut callback as &mut dyn FnMut(u32) -> ());
> | ------------^^^^^^^^^^^^^------------------------------
> | | |
> | | borrowed value does not live long enough
> | argument requires that `callback` is borrowed for `'a`
> | }
> | - `callback` dropped here while still borrowed
Example:
use std::any::Any;
use std::mem;
use std::rc::Rc;
use std::cell::RefCell;
struct Event<'a> {
obs: Vec<&'a mut dyn FnMut(u32) -> ()>,
}
impl<'a> Event<'a> {
fn subscriber<F: FnMut(u32) -> () + 'a>(&mut self, mut callback: F) {
self.o.push(&mut callback as &mut dyn FnMut(u32) -> ());
}
}
fn main () {
let mut e = Event {obs: Vec::new()};
let x = 3;
e.subscriber(|n| {x+n;});
}
the
callback
parameter uses theF
generic which is definitely constrained by the lifetime'a
. But the error is still appearing stating that thecallback
parameter does not live long enough.
callback
lives long enough, but the problem is you're not storing the callback
you received, you're storing it converted to a trait object (dyn
) and that trait object's data has to be owned by something.
I originally used
Box<T>
as my container for thedyn FnMut(u32)
, but theBox<T>
requires the callback to be'static
No it doesn't. This compiles:
struct Event<'a> {
obs: Vec<Box<dyn FnMut(u32) -> () + 'a>>,
}
impl<'a> Event<'a> {
fn subscriber<F: FnMut(u32) -> () + 'a>(&mut self, callback: F) {
self.obs.push(Box::new(callback));
}
}
Then with one more change, your example will compile: define x
before e
so that x
lives longer than e
:
fn main() {
let x = 3;
let mut e = Event {obs: Vec::new()};
e.subscriber(|n| {x+n;});
}