0

Let's say we have a struct containing callbacks:

use std::collections::HashMap;

struct Struct {
    callbacks: HashMap<char, Box<Fn(&mut Struct)>>,
}

impl Struct {
    fn new() -> Struct {
        Struct {
            callbacks: HashMap::new(),
        }
    }

    fn add_callback<F: Fn(&mut Struct) + 'static>(&mut self, key: char, callback: F) {
        self.callbacks.insert(key, Box::new(callback));
    }

    fn invoke_callback(&mut self, key: char) {
        if let Some(callback) = self.callbacks.get(&key) {
            callback(self); // NOTE: error here
        }
    }

    fn print(&mut self) {
        println!("Mutably print");
    }
}

fn main() {
    let mut strct = Struct::new();
    strct.add_callback('a', |strct| {
        strct.print();
    });
    strct.invoke_callback('a');
}

With this code, I have the following error:

src/main.rs:20:22: 20:26 error: cannot borrow `*self` as mutable because `self.callbacks` is also borrowed as immutable [E0502]
src/main.rs:20             callback(self);
                                    ^~~~
src/main.rs:19:33: 19:47 note: previous borrow of `self.callbacks` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.callbacks` until the borrow ends
src/main.rs:19         if let Some(callback) = self.callbacks.get(&key) {
                                               ^~~~~~~~~~~~~~
src/main.rs:21:10: 21:10 note: previous borrow ends here
src/main.rs:19         if let Some(callback) = self.callbacks.get(&key) {
src/main.rs:20             callback(self);
src/main.rs:21         }
                       ^
error: aborting due to previous error
error: Could not compile `so`.

How can I invoke the callback that takes a mutable reference to self?

The only way I found was to remove the callback from the HashMap and inserting it back:

fn invoke_callback(&mut self, key: char) {
    if let Some(callback) = self.callbacks.remove(&key) {
        callback(self);
        self.callbacks.insert(key, callback);
    }
}

I wonder if there is a better way of invoking a callback contained in a struct.

antoyo
  • 11,097
  • 7
  • 51
  • 82
  • Also relevant: http://stackoverflow.com/q/29540167/155423; http://stackoverflow.com/q/38027461/155423. – Shepmaster Jul 09 '16 at 19:15
  • In the [post you linked](http://stackoverflow.com/questions/32044301/cannot-pass-self-as-callback-parameter-due-to-double-borrowing), we see a similar solution to what I already posted in this question. I wonder if there is a better way because it seems to be a recurrent issue in Rust. – antoyo Jul 09 '16 at 20:15
  • I'm not really sure how SO prefers to handle the case of "I don't like the existing answers, are there any better ones". I believe you could open a bounty on the existing question to draw attention to it and include a custom reason describing why you don't like the current answer and ask for a better one. If you can find something in Meta that indicates it's OK to open new questions seeking newer / better / updated answers to a previous question, I'd be happy to un-duplicate this one. – Shepmaster Jul 09 '16 at 20:23

0 Answers0