Cannot move out of `self.event_loop` which is behind a mutable reference

Hi, I've just started a tutorial on how to initialize a simple application with Vulkan as an excuse to exercise my rust skills. It's been two weeks since I've started with rust and I've never stumbled in this kind of error...
Here the compiler is telling me that i can't move the event_loop object out self because it lies behind a mutable reference.
What i don't understand specifically is:
- Why is a move even occurring in this case?
- Why can't i move some B out of some else A if i tell the compiler that A is mutable?

Here the full error:

error[E0507]: cannot move out of `self.event_loop` which is behind a mutable reference
  --> src/main.rs:33:13
   |
33 |             self.event_loop.run(move |event, _, _| {
   |             ^^^^^^^^^^^^^^^ move occurs because `self.event_loop` has type `winit::event_loop::EventLoop<()>`, which does not implement the `Copy` trait

Code:

struct HelloTriangleApplication {
    event_loop: EventLoop<()>
}

impl HelloTriangleApplication {
    pub fn init() -> Self {
        let event_loop = Self::init_window();
        Self {
            event_loop
        }
    }

    fn init_window() -> EventLoop<()> {
        let event_loop = EventLoop::new();
        let _window = WindowBuilder::new()
            .with_title("Vulkan tutorial")
            //.with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT)))
            .build(&event_loop);
        event_loop
    }

    fn main_loop(&mut self) {
        loop {
            let mut done: bool = false;
            self.event_loop.run(move |event, _, _| {
                if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = event {
                    done = true
                }
                if done {
                    return;
                }
            });
        }
    }
}

If you move out of the pointed value of the reference, the reference would point to invalidated/uninitialized ("garbage") data.

It seems like the run() method takes the event loop by value.

1 Like

You may be interested in using the .run_return() method instead, given your &mut-based pattern.

1 Like

What if i really want to stick with .run()? given the fact that the documentation says: You are strongly encouraged to use run, unless the use of this is absolutely necessary.
How would the structure of the code i provided change? Thanks.

Ok, this makes a lot of sense. Then whats the right way of using that .run() method?

If you change main_loop to take self instead of &mut self, then you are taking ownership of self, and when you have ownership you will be able to destroy fields of the struct.

1 Like

According to the API, that run() method is the final event loop: no need to loop { yourself since it will loop for you, and no code located after the loop will ever be executed (it's a diverging function, as shown by the -> ! signature). I'd thus do:

-   fn main_loop(&mut self) {
+   fn main_loop(self) {
-       loop {
-           let mut done: bool = false;
            self.event_loop.run(move |event, _, next_control_flow| {
+               *next_control_flow = ControlFlow::Poll;
                if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = event {
-                   done = true
+                   *next_control_flow = ControlFlow::Exit;
+                   return;
                }
-               if done {
-                   return;
-               }
            });
-       }
    }

That is:

fn main_loop(self) {
    self.event_loop.run(move |event, _, next_control_flow| {
        *next_control_flow = ControlFlow::Poll;
        if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = event {
            *next_control_flow = ControlFlow::Exit;
            return;
        }
    });
}
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.