1

This code doesn't compile. But it fails on the last line marked Err, not the line marked Ok. Why can we assign a mutable reference to an immutable reference type but not use it after the assignment?

fn main() {
    let mut x = 10;
    let mut y = 20;
    let mut r = &x;
    r = &mut y; //Ok
    *r = 30;    //Err
}
TSK
  • 509
  • 1
  • 9

2 Answers2

3

Why can we ... not use it after the assignment?

The variable r is an immutable reference of type &i32; it does not have mutable access to the referenced value. So it makes sense the compiler would reject your attempt to assign through it.

Why can we assign a mutable reference to an immutable reference type ...?

Why wouldn't you be able to downgrade a mutable reference into an immutable one? The latter is a strict subset of the former. If you were asking about the technicalities instead of the practicalities, its because &mut T to &T is a supported coercion.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
1

If we add explicit types to your code as inferred by the compiler:

fn main() {
    let mut x: i32 = 10;
    let mut y: i32 = 20;
    let mut r: &i32 = &x;
    r = &mut y; //Ok
    *r = 30;    //Err
}

We see that r has type &i32 and not &mut i32, so of course we can't use r to modify the referenced value.

Why can we still do r = &mut y? Simply because we can always use a &mut reference anywhere a & reference is expected (because &mut T implements Deref<Target=T>, allowing coercion to happen).

Jmb
  • 18,893
  • 2
  • 28
  • 55
  • Not `Deref` is what allows the coercion, [it is a special case in the compiler](https://github.com/rust-lang/rust/blob/7feb003882ecf7699e6705b537673e20985accff/compiler/rustc_hir_typeck/src/coercion.rs#L325). – Chayim Friedman Oct 24 '22 at 07:27