Reputation: 1164
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:
GameEngine::handle_event()
to handle itThe 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));
}
}
}
}
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
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
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