The problem
receiver.attach API requires a 'static closure, that is, a closure that is statically guaranteed not to carry a dangling pointer/reference at any point.
In your case, however, the closure is capturing self: &'_ Self, i.e., a reference to Self guaranteed to be valid only for some anonymous lifetime '_ that may very well be shorter than 'static. In other words, the self: &'_ Self may very well dangle at some point in the program, which is not acceptable given the API requirements of receiver.attach.
The solution
Any time this kind of issues happens, it comes from the fact that one must avoid borrowing, which means that taking ownership is required.
You thus cannot capture a &'_ Self or a &'_ mut Self, but a Self, Box<Self>, Arc<Self>, etc. : something that owns Self.
So the first reflex is to self.clone(), to effectively get a value of type Self:
let captured: Self = self.clone();
receiver.attach(None, move |action| this.do_action(action));
- (
move is usually required in this kind of cases to tell Rust "to capture owned variables rather than references / borrows"; you can read this nice blog post to understand what a closure "capture" actually is)
Something along these lines should compile.
The only issue with this is that the whole object is "copied" (cloned) when in other languages just copything the pointer would have sufficed.
If that's what you want to do, the way to express that in Rust is by using the Arc wrapper (or Rc as a micro-optimization for a guaranteed single-threaded context): when an Arc is .cloned, it's just a pointer that is copied:
fn do_action(&self, action: Action) -> glib::Continue {
match action {
Action::Show(monster) => {
let single = Single::new(monster);
self.header.change_title(&single.name);
self.content.stack.set_visible_child(&single.container);
}
}
glib::Continue(true)
}
fn connect_events(self: Arc<Self>) {
let receiver = self.receiver.borrow_mut().take().unwrap();
let self_clone = Arc::clone(&self);
receiver.attach(None, move |action| self_clone.do_action(action));
self.window.connect_delete_event(move |_, _| {
gtk::main_quit();
gio::signal::Inhibit(false)
});
}
or something along these lines (ideally you manage to just Arc-wrap the fields required for the .do_action()).