Mutable borrow starting in previous iteration of loop

Hi,

Consider the following simple/example code:

struct Key;

struct Door<'a> {
    key: &'a Key,
}

struct Room<'a> {
    door: Door<'a>,
}

impl<'a> Room<'a> {
    /// Create a room out of a key... Yeah, it's just a stupid example ;-) 
    fn new(key: &'a Key) -> Self {
        let door = Door{ key };
        Self{ door }
    }
    
    fn get_door(&self) -> &Door {
        &self.door
    }
    
    fn get_door_as_mut(&mut self) -> &'a mut Door {
        &mut self.door
    }
}

fn main() {
    let key = Key;
    let mut room = Room::new(&key);
    
    for _ in 0..2 {
        let _d = room.get_door();
        let _md = room.get_door_as_mut();
    }
}

This code doesn't compile since, with the for loop, the borrow checker complains about:

   |
32 |         room.get_door_as_mut();
   |         ^^^^ mutable borrow starts here in previous iteration of loop

But honestly I cannot understand why the mut reference outlives the loop scope. I mean _md should go out of scope at next line and so there _d should not have trouble to get immutable reference of rooom.

Could you help me understanding why of this behaviour and solve it in an elegant an idiomatic way?

Thank you.

I like to imagine it like this...

On every iteration of your loop a new variable is created that gets to own your your stuff. It happens to recycle the same name. "_d" in this case. But they are not the same.

If we think of the loop as unrolled it looks like this:

    let _d0 = room.get_door();
    let _md0 = room.get_door_as_mut();

    let _d1 = room.get_door();
    let _md1 = room.get_door_as_mut();
    ...

Well you can't have a _d0, _d1, ... all aliasing and owning the same thing.

1 Like

You've annotated lifetimes incorrectly, so that's why. It should be,

    fn get_door(&self) -> &Door<'a> {
        &self.door
    }
    
    fn get_door_as_mut(&mut self) -> &mut Door<'a> {
        &mut self.door
    }
2 Likes

On top of other answers, you could do something to the door like this:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=501104557cd5659b978000455145006e
You don't really need to assign it to a variable.

Thanks! It was so simple and clean (and I was so stupid)! :laughing:

You're right, but actually, in my real scenario, my struct are spread in different modules and so I cannot directly access to private fields, so because of that I have implemented get_xxx and get_xxx_as_mut methods.

I don't mean to question your design but this sounds a bit strange. If fields are private and no one outside can access them - then maybe handing them out mutably isn't such a good idea? Although it's difficult to say without broader context.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.