0

I have the following code that compiles and runs without any issues -

#[derive(Debug)]
pub struct A<'a> {
    field: &'a mut String
}

fn main() {
    let mut b = "Hello".to_owned();
    let a = A { field: &mut b };
    let c = A { field: a.field };

    c.field.push('+');
    a.field.push('+');
    //println!("{:?}", c);
    // println!("{:?}", a);
}

But I am confused as to why this code is working, or even compiling, for the following reasons -

  1. It seems like we are holding two mutable references to the same object b. This is evident since both c.field.push('+'); and a.field.push('+'); succeed.

  2. Why does this statement - let c = A { field: a.field };, not move field out of A (since mutable references are not copyable) and invalidate A?

Kshitij Jain
  • 13
  • 1
  • 3
  • 1
    After `c.field.push('+')`, the compiler drops `c` so that `field` is returned exclusively to `a`. Before non-lexical lifetimes, you would have had to write [this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=90ae5ccedd58c2d987d7a038d062c11d). – E_net4 Jan 30 '21 at 22:53
  • 1
    See also: https://stackoverflow.com/q/45095523 (clarifies the second question further; it is usually better to stick to one question per post). – E_net4 Jan 30 '21 at 22:54
  • I agree non-lexical lifetimes are half of the story here; the other half is implicit reborrowing. However, it may be easier to understand an intuitive explanation: it's not forbidden because it's just *not wrong*. The borrow checker's job is not to make you jump through hoops; it's to forbid code that causes undefined behavior, and this code doesn't, so the borrow checker is fine with it. The specific compiler internals that let the borrow checker understand that it's OK, and the historical names of features that go into it, aren't necessarily helpful, so I wouldn't sweat it too much :-) – trent Jan 30 '21 at 23:19

0 Answers0