Michael Pacheco
Michael Pacheco

Reputation: 1164

Cannot borrow `*self` as mutable more than once at a time when using an iterator

I'm trying to learn rust making a game with SDL2. I have a struct GameEngine which has ownership of some variables to control the game state.

The method GameEngine::run() is responsible to manage the game loop. I want this method to do 2 things:

  1. Check if some event is related to closing the game and in this case break the loop
  2. For any other kind of event I want to call a method GameEngine::handle_event() to handle it

The problem is that the compiler is refusing to accept my code telling me I'm trying to borrow self as mutable more than once. The first borrow happen on this line:

let event_poll_iterator = self.event_pump.poll_iter();

and the second on this:

self.handle_event(event);

As I'm a newbie in Rust, I'm getting stuck in this error.

The complete code:

pub mod engine {
    use std::time::Duration;

    use sdl2::{EventPump, Sdl};
    use sdl2::event::Event;
    use sdl2::keyboard::Keycode;
    use sdl2::pixels::Color;
    use sdl2::render::WindowCanvas;

    fn get_canvas(sdl_context: &Sdl) -> WindowCanvas {
        let video_subsystem = sdl_context.video().unwrap();

        let window = video_subsystem
            .window("SDL2 Snake Game", 800, 600)
            .position_centered()
            .opengl()
            .build()
            .map_err(|e| e.to_string()).unwrap();

        let mut canvas = window.into_canvas().build().map_err(|e| e.to_string()).unwrap();

        canvas.set_draw_color(Color::BLACK);

        canvas
    }

    pub struct GameEngine {
        context: Sdl,
        event_pump: EventPump,
        canvas: WindowCanvas,
    }

    impl GameEngine {
        pub fn new() -> Self {
            let context = sdl2::init().unwrap();
            let canvas = get_canvas(&context);
            let event_pump = context.event_pump().unwrap();
            GameEngine { context, canvas, event_pump }
        }

        fn redraw(&mut self) {
            self.canvas.clear();
            self.canvas.present();
        }

        fn handle_event(&mut self, event: Event) {
            todo!()
        }

        pub fn run(&mut self) {
            'game_loop: loop {
                let event_poll_iterator = self.event_pump.poll_iter();

                for event in event_poll_iterator {
                    match event {
                        Event::Quit { .. }
                        | Event::KeyDown {
                            keycode: Some(Keycode::Escape),
                            ..
                        } => break 'game_loop,
                        _ => {
                            self.handle_event(event);
                        }
                    }
                }

                self.redraw();
                std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 30));
            }
        }
    }
}

Edit

I could reproduce the same problem (I think) with a much smaller example:

struct List {
    v: Vec<u32>
}

impl List {
    fn increment(&mut self, x: &mut u32) {
        *x += 1;
    }

    fn iter(&mut self) {
        for x in &mut self.v {
            self.increment(x);
        }
    }
}

fn main() {
    let mut list = List { v: vec![1, 2, 3] };
    list.iter();
    assert!(list.v == vec![2, 3, 4]);
}

Error log:

λ cargo run
   Compiling rustlings v4.7.1 (/home/luizalabs/repositories/rust/rustlings)
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:12:13
   |
11 |         for x in &mut self.v {
   |                  -----------
   |                  |
   |                  first mutable borrow occurs here
   |                  first borrow later used here
12 |             self.increment(x);
   |             ^^^^^^^^^^^^^^^^^ second mutable borrow occurs here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `rustlings` due to previous error

Upvotes: 1

Views: 1132

Answers (2)

STO
STO

Reputation: 10658

Tried to simplify your example

fn main() {
    let i: i32 = 4326;

    let b = i.to_le_bytes();

    for i in 0..4 {
        println!("{}", b[i]);
    }
}

pub struct GameEngine {
    event_pump: EventPump,
}

pub struct EventPump {
}

impl EventPump {
    pub fn poll_iter(&mut self) -> Vec<i32>  {
        vec![0, 1, 2]
    }
}

impl GameEngine {
    pub fn new() -> Self {
        GameEngine {
            event_pump: EventPump { },
        }
    }

    fn redraw(&mut self) {
    }

    fn handle_event(&mut self, _event: i32) {
        todo!()
    }

    pub fn run(&mut self) {
        loop {
        let ep = self.event_pump.poll_iter();
            let event_poll_iterator = ep.iter();

            for event in event_poll_iterator {
                match event {
                    _ => {
                        self.handle_event(*event);
                    }
                }
            }

            self.redraw();
        }
    }
}

Hope without losing sense. Seems it compiled ok. It changes Iter to vector instance but I'm not sure if that matters.

Upvotes: 0

obr
obr

Reputation: 186

The problem is, self.handle_event could modify whatever you are iterating over (in this case event_poll_iterator). If you are modifying what the iterator is iterating over, you might want to consider cloning the iterator. If self.handle_event isn't modifying the iterator, you have to show the borrow checker that you are not modifying the iterator. One option is to inline self.handle_event. Another option is to pass whatever you are modifying as mutable to self.handle_event. Here is a simple example of what is going on:

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32
}

struct Points {
    points: Vec<Point>,
    num_points: usize
}

impl Points {
    fn bar(&mut self, point: &mut Point) {
        println!("{:?}", point)
    }

    fn foo(&mut self) {
        for p in &mut self.points {
            self.bar(p);
        }
    }
}

Inlining would change foo as such:

fn foo(&mut self) {
    for p in &mut self.points {
        println!("{:?}", p); // modified line
    }
}

Upvotes: 1

Related Questions