Creating a callback system using closures

I am trying to do something like a “callback system”. For example, it has a window and several buttons. The window sets callbacks for each button. Both callbacks should change the state of the window. The compiler does not allow capture &self in my closures / callbacks, and I don't know how to make it work.

Are there common patterns for callbacks that I have to follow?

This is a simple example, since all components have the same lifetime. What if the components have different lifetimes?

 struct Button<'a> { f: Option<Box<Fn() + 'a>>, } impl<'a> Button<'a> { fn new() -> Button<'a> { Button { f: None } } fn set<T: Fn() + 'a>(&mut self, f: T) { self.f = Some(Box::new(f)); } fn unset(&mut self) { self.f = None; } fn call(&self) { match self.f { Some(ref f) => f(), None => () } } } struct Window<'a> { btn: Button<'a>, //btns: Vec<Button<'a>>, } impl<'a> Window<'a> { fn new() -> Window<'a> { Window { btn: Button::new() } } fn hi(&mut self) { // self is mutable println!("callback"); } fn run(&mut self) { // Compile error: cannot infer an appropriate lifetime for // capture of `self` by closure due to conflicting requirements self.btn.set(|| self.hi()); // How to make it work? self.btn.call(); self.btn.unset(); } } fn main() { let mut wnd = Window::new(); wnd.run(); } 
+7
closures rust
source share
1 answer

In this line you will encounter the following problems:

 self.btn.set(|| self.hi()); 

Here you need to take self as mutable to change btn . You are also trying to borrow self as mutable in closure. This will immediately cause problems because Rust does not allow you to have multiple mutable references to the same object (known as aliasing). This is a fundamental part of language memory security guarantees.

In addition, you are conceptually trying to set up a link loop - Window knows about Button and Button knows about Window . While this is possible, often this is not what you want. Once links have a loop, it is very difficult to untangle them. You can also find other questions that ask about creating graphs in Rust (as opposed to trees) to see similar problems that other people had.

Ideally, you can structure your code like a tree. Here, I chose what Button can know about Window , but not vice versa:

 struct Button<'a> { f: Option<Box<FnMut() + 'a>>, } impl<'a> Button<'a> { fn new() -> Button<'a> { Button { f: None } } fn set<T: FnMut() + 'a>(&mut self, f: T) { self.f = Some(Box::new(f)); } fn unset(&mut self) { self.f = None; } fn call(&mut self) { match self.f { Some(ref mut f) => f(), None => () } } } struct Window; impl Window { fn hi(&mut self) { println!("callback"); } } fn main() { let mut wnd = Window; let mut btn = Button::new(); btn.set(|| wnd.hi()); btn.call(); btn.unset(); } 
+6
source share

All Articles