Mutable borrow starts here in previous iteration of loop


#1

I used to work with C++ / Python, but I am a total newbie to rust.

I wrote the fellowing code

#[derive(Debug)]
pub struct Foo {}

#[derive(Debug)]
pub struct Bar {
    foo: Foo,
}

#[derive(Debug)]
pub struct Baz<'a> {
    foo_ref: &'a Foo,
}

impl Bar {
    pub fn new() -> Self {
        Self { foo: Foo {} }
    }

    pub fn get_foo(&mut self) -> &Foo {
        return &self.foo;
    }
}

fn f1(bar: &mut Bar) {
    let mut bazes = Vec::<Baz>::new();
    for i in 1..10 {
        let foo = bar.get_foo();
        let baz = Baz { foo_ref: foo };
        bazes.push(baz);
    }
}

fn f2() {
    let mut bar = Bar::new();
    f1(&mut bar);
}

But rustc tell me that

error[E0499]: cannot borrow *bar as mutable more than once at a time
–> examples\rex.rs:92:19
|
| let foo = bar.get_foo();
| ^^^ mutable borrow starts here in previous iteration of loop
error: aborting due to previous error

That’s really confusing for me. I guess the cause is: in f1, bazes extends lifetime of foo, and signature of get_foo requires &mut bar to live longer than bazes, which make it impossible to be mutable borrowed again.

I don’t know how to fix this. Can anyone please help me?


#2

Pretty much.

Why are you using &mut Bar? You aren’t mutating anything. This would work fine if you weren’t using mutable borrows. Even just making get_foo work on an immutable borrow instead should work.


#3

Thank you for your reply.

I use &mut because I need to modify it, the code I posted is simplified.

Recently I am working on my own physics engine for learning purpose (both rust and game physics). My code is like this:

#[derive(Debug)]
pub struct RigidBody {}

impl RigidBody {
    pub fn new() -> Self {
        Self {}
    }

    pub fn update(&mut self) {}
}

#[derive(Debug)]
pub struct Simulator {
    rbs: Vec<RigidBody>,
}

impl Simulator {
    pub fn new() -> Simulator {
        Simulator { rbs: vec![] }
    }

    pub fn new_rigid_body(&mut self) -> &RigidBody {
        let rb = RigidBody::new();
        self.rbs.push(rb);
        return self.rbs.last().unwrap();
    }
}

#[derive(Debug)]
struct Ball<'a> {
    rb: &'a RigidBody,
}

impl<'a> Ball<'a> {
    fn new(rb: &'a RigidBody) -> Self {
        Self { rb }
    }
}

const N_BALLS: i32 = 4;

fn create_balls(sim: &mut Simulator) -> Vec<Ball> {
    let mut balls = Vec::<Ball>::new();

    for i in 0..N_BALLS {
        let rb = sim.new_rigid_body();
        let ball = Ball::new(rb);
        balls.push(ball);
    }
    return balls;
}

I need to accumulate a list of balls (referencing rigidbodies in simulator).


#4

You’re mutating something while keeping references to it. That’s just not going to work.

You have to redesign your code to not do that. Either don’t use references in Ball (use some other kind of identifier), or have creation and lookup as separate phases.


#5

A common workaround is using Arenas to store values and using indices into arena to refer to values. A good crate that implements the Arena pattern is generational-arena


#6

thank you, i’ll check it out.


#7

Alright, I guess i have to redesign my code. Thank you very much for your advices.


#8

Rust actually saved you from a nasty memory bug here! Pushing to a vector may cause its contents to be reallocated somewhere else, causing all of the already-existing Balls to have dangling pointers.