1

Here's the code, since a is declared as immutable, we can't obtain a mutable reference from a, right? But this one has compiled, why is that?

struct Foo;

fn main() {
    let a = &mut Foo;
    a.mut_ref();
}

impl Foo {
    fn mut_ref(&mut self) { }
}

code-link

TENX
  • 23
  • 5
  • You don't actually obtain a mutable reference to `a` in this code, but this is still a good question. I know it *is* this way but I couldn't explain it mechanically. – trent Aug 19 '20 at 03:45

1 Answers1

5

The type of the variable a is &mut Foo, i.e. a itself is a mutable reference to a Foo object. Mutating a would mean to make it point to a different Foo object. Since a itself is immutable, you can't change what a is pointing to, and your code does not disprove this in any way.

Your code simply passes the &mut Foo as the self parameter to mut_ref() – note that the type of self is also &mut Foo. No auto-dereferencing is happening – a already has exactly the type that is epxected for the self parameter. However, we are triggering an implicit reborrow here, so the call is equivalent to Foo::mut_ref(&mut *a). This implicit reborrow isn't what's making the code work, though – moving the mutable reference out of a would also be perfectly allowed.

While a is immutable as a variable, it's still a mutable reference, so you can mutate the Foo object it's pointing to (assuming Foo had any state to mutate). You can't obtain a mutable reference to a, which would need to have the type &mut &mut Foo.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841