2
votes

I tried to make the example code as simple as possible

struct Level;

pub struct GameManager<'self>{
    lvl: Level,
    actors: ~[Actor<'self>]
}
struct Actor<'self>{
    lvl: &'self Level
}
impl<'self> GameManager <'self> {
    pub fn new() -> GameManager{
        GameManager {lvl: Level,actors: ~[]}
    }
    fn spawn_actor<'r>(&'r self) -> Actor<'r>{
        Actor{lvl: &'r self.lvl}
    }
}
fn main() {
    let mut gm = GameManager::new();

    let mut actor1 = gm.spawn_actor();

    gm.actors.push(actor1);


}

Error:

/home/maik/source/test.rs:23:4: 23:13 error: cannot borrow `gm.actors` as mutable because it is also borrowed as immutable
/home/maik/source/test.rs:23     gm.actors.push(actor1);
                                 ^~~~~~~~~
/home/maik/source/test.rs:21:21: 21:23 note: second borrow of `gm.actors` occurs here
/home/maik/source/test.rs:21     let mut actor1 = gm.spawn_actor();

As you can see I want the GameManager to spawn an actor. A GameManager as a Level and I want all spawned actors to have a reference to the GameManager's Level.

Can someone explain this error to me? How do I fix it?

2

2 Answers

3
votes

It seems it is not possible in Rust.

But I found a solution to do this, I just needed to encapsulate a little bit more, like

struct Level;
pub struct ActorController{
    lvl: Level
}
pub struct GameManager<'self>{
    actors: ~[Actor<'self>],
    actor_controller: ActorController
}
struct Actor<'self>{
    lvl: &'self Level
}
impl ActorController {
    fn spawn_actor<'r>(&'r self) -> Actor<'r>{
        Actor{lvl: &'r self.lvl}
    }
}
impl<'self> GameManager <'self> {
    pub fn new() -> GameManager{
        GameManager {actors: ~[], actor_controller: ActorController{lvl: Level}}
    }
}
fn main() {
    let mut gm = GameManager::new();

    let actor1 = gm.actor_controller.spawn_actor();

    gm.actors.push(actor1);


}
2
votes

You have an immutable borrow to gm inside Actor and can't modify it as long as it exists.

You can change it into a const borrow as in :

struct Actor<'self>{
    lvl: &'self const Level
}

But I'm not sure it will still exists on next rust releases. (They try to get rid of it in the compiler at least)

Another alternative would be to use @-pointers. You won't have any borrow issue then :)

Edit : Here's the whole code with const that compiles

struct Level;

pub struct GameManager<'self>{
    lvl: Level,
    actors: ~[Actor<'self>]
}
struct Actor<'self>{
    lvl: &'self const Level
}
impl<'self> GameManager <'self> {
    pub fn new() -> GameManager{
        GameManager {lvl: Level,actors: ~[]}
    }
    fn spawn_actor<'r>(&'r const self) -> Actor<'r>{
        Actor{lvl: &'r const self.lvl}
    }
}
fn main() {
    let mut gm = GameManager::new();

    let mut actor1 = gm.spawn_actor();

    gm.actors.push(actor1);
}