2

I'm trying to implement a Dispatcher that holds a HashMap of closures which contain methods from other structs. The Dispatcher should be able to be passed around as it represents one event handler with a state for many clients.

With Dispatcher::add_method, it should be possible to add new closures to the HashMap:

struct Dispatcher<'a> {
    methods: HashMap<String, Box<dyn FnMut(i32) + 'a>>,
}

impl<'a> Dispatcher<'a> {
    ...
    pub fn add_method(&mut self, name: String, method: impl FnMut(i32) + 'a) {
        self.methods.insert(name, Box::new(method));
    }
    ...
}

An example of a struct that uses the Dispatcher and adds new methods to it:

struct Example {
    num: i32,
}
impl Example {
    pub fn init<'a>(&'a mut self, dispatcher: &'a mut Dispatcher<'a>) {
        dispatcher.add_method("test".to_string(), move |num| {
            self.num = num;
        });
    }
}

I don't know how to initialize the Example to add the closures to the Dispatcher. I'm trying this but the result is a compilation error.

struct Handler<'a>{
    example: Example,
    dispatcher: Dispatcher<'a>
}

impl<'a> Handler<'a>{
    fn new() -> Self {

        let mut dispatcher = Dispatcher::new();
        let mut example = Example::new();

        example.init(&mut dispatcher);

        Handler{
            example: example,
            dispatcher: dispatcher,
        }
    }
}

I understand that I'm trying to move out an borrowed value, but I have to borrow the Dispatcher for the init method of the Example. How should I do it otherwise?

Playground

error[E0515]: cannot return value referencing local variable `dispatcher`
  --> src/lib.rs:46:9
   |
44 |           example.init(&mut dispatcher);
   |                        --------------- `dispatcher` is borrowed here
45 | 
46 | /         Handler {
47 | |             example: example,
48 | |             dispatcher: dispatcher
49 | |         }
   | |_________^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing local variable `example`
  --> src/lib.rs:46:9
   |
44 |           example.init(&mut dispatcher);
   |           ------- `example` is borrowed here
45 | 
46 | /         Handler {
47 | |             example: example,
48 | |             dispatcher: dispatcher
49 | |         }
   | |_________^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `example` because it is borrowed
  --> src/lib.rs:47:22
   |
39 |   impl<'a> Handler<'a> {
   |        -- lifetime `'a` defined here
...
44 |           example.init(&mut dispatcher);
   |           ------- borrow of `example` occurs here
45 | 
46 | /         Handler {
47 | |             example: example,
   | |                      ^^^^^^^ move out of `example` occurs here
48 | |             dispatcher: dispatcher
49 | |         }
   | |_________- returning this value requires that `example` is borrowed for `'a`

error[E0505]: cannot move out of `dispatcher` because it is borrowed
  --> src/lib.rs:48:25
   |
39 |   impl<'a> Handler<'a> {
   |        -- lifetime `'a` defined here
...
44 |           example.init(&mut dispatcher);
   |                        --------------- borrow of `dispatcher` occurs here
45 | 
46 | /         Handler {
47 | |             example: example,
48 | |             dispatcher: dispatcher
   | |                         ^^^^^^^^^^ move out of `dispatcher` occurs here
49 | |         }
   | |_________- returning this value requires that `dispatcher` is borrowed for `'a`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Giom
  • 21
  • 3
  • It's hard to answer your question because it doesn't include a [MRE]. We can't tell what crates (and their versions), types, traits, fields, etc. are present in the code. It would make it easier for us to help you if you try to reproduce your error on the [Rust Playground](https://play.rust-lang.org) if possible, otherwise in a brand new Cargo project, then [edit] your question to include the additional info. There are [Rust-specific MRE tips](//stackoverflow.com/tags/rust/info) you can use to reduce your original code for posting here. Thanks! – Shepmaster Jul 23 '19 at 14:34
  • It looks like your question might be answered by the answers of [How can I modify self in a closure called from a member function?](https://stackoverflow.com/q/28597380/155423); [How to use struct self in member method closure](https://stackoverflow.com/q/48717833/155423); [Mutably borrow one struct field while borrowing another in a closure](https://stackoverflow.com/q/36379242/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 23 '19 at 14:36
  • I looked through your links and I found something wrong in my HashMap using Fn and not FnMut. Unfortunately I didn't figure out how to fix my main Error. So tried to remove everything unnecessary and I added a Playground example for clearness. Thanks for your advices. – Giom Jul 23 '19 at 19:28
  • It looks like your modified question might be answered by the answers of [Is there any way to return a reference to a variable created in a function?](https://stackoverflow.com/q/32682876/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 23 '19 at 19:28
  • See also [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132/155423) – Shepmaster Jul 23 '19 at 19:30

0 Answers0