0

Consider the following code:

struct Event {
    id: i32,
}

struct EventsLoop;
impl EventsLoop {
    pub fn new() -> EventsLoop {
        EventsLoop {}
    }

    pub fn poll_events<F>(&mut self, _callback: F)
    where
        F: FnMut(Event),
    {
        // gets event and passes it to the callback
    }
}

struct Store {
    events_loop: EventsLoop,
    running: bool,
}

fn main() {
    let store = setup_store();
    run_app(store);
}

fn setup_store() -> Store {
    Store {
        events_loop: EventsLoop::new(),
        running: true,
    }
}

fn run_app(mut store: Store) {
    let mut e_loop = store.events_loop;
    e_loop.poll_events(|event| {
        // poll_events needs EventsLoop as a mutable reference
        match event {
            Event { id: -1 } => {
                store.running = false;
            }
            _ => { /* store is used in other events */ }
        }
    })
}

This causes the compiler to complain:

error[E0382]: capture of partially moved value: `store`
  --> src/main.rs:38:24
   |
37 |     let mut e_loop = store.events_loop;
   |         ---------- value moved here
38 |     e_loop.poll_events(|event| {
   |                        ^^^^^^^ value captured here after move
   |
   = note: move occurs because `store.events_loop` has type `EventsLoop`, which does not implement the `Copy` trait

I have a closure that needs to either borrow or take ownership of store. At the same time I need store.events_loop as a mutable reference (because of its method poll_events). I thought that maybe I could get around the multiple mutable borrowing problem by passing ownership of the EventsLoop from store to the function scope. So my first question is:

  1. Can this problem be solved by somehow moving the EventsLoop out of store?

Another solution I thought of was passing store to run_app as an immutable reference, and wrapping the field running in a Cell, but then I would need some kind of smart pointer to get the EventsLoop as a mutable reference. So that leads me to my second question:

  1. Is there a way to extract events_loop from store as a mutable reference when store was passed as an immutable reference?

Edit:

My apologies for not having an MVCE in my first post. The current example should reproduce the problem. It has been suggested this question may be duplicate to Mutably borrow one struct field while borrowing another in a closure The situation here is similar but different. The question in the link is about two fields in a struct, using one field from a struct in a closure that is passed to a method on the other field. This question is about using a struct in a closure, that closure being passed to a method of a field inside that struct. The point here is that I would like to be able to access the store in the closure, while also getting the events loop from the store. The idea is that all data structures created at initialization in setup_store - including the events loop - go into a single struct.

Peerhenry
  • 199
  • 1
  • 4
  • I believe your question is answered by the answers of [Mutably borrow one struct field while borrowing another in a closure](https://stackoverflow.com/q/36379242/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Aug 17 '18 at 14:17
  • 1
    The duplicate applied to your question: `let running = &mut store.running; store.events_loop.poll_events(|event| /*...*/ *running = false; /*...*/)`. – Shepmaster Aug 17 '18 at 15:06
  • Regarding your edit: no, you can't do that with plain references. See [Mutable self while reading from owner object](https://stackoverflow.com/q/28385339/155423); [Borrowing references to attributes in a struct](https://stackoverflow.com/q/25513755/155423); [Passing mutable self reference to method of owned object](https://stackoverflow.com/q/30681468/155423). Note this last one has answers with many different alternatives. – Shepmaster Aug 17 '18 at 15:43
  • Note that these are all the same root issue. Something has taken a mutable reference to `store.events_loop` and thus nothing else may be allowed to access that. By passing `store` to another function, it would be able to access `store.events_loop`, breaking the guarantees. Rust must prevent this. – Shepmaster Aug 17 '18 at 15:52
  • Note that, according to your edit, the code you have provided is *still* not a MCVE. *The code you have provided* is solved by applying the linked question. If the code you have provided isn't representative of the problem you are having, there's not much we can do to help. – Shepmaster Aug 20 '18 at 13:10

0 Answers0