It seems that I cannot mutate anything if there is any immutable reference in my chain of dereferencing. A sample:
fn main() {
let mut x = 42;
let y: &mut i32 = &mut x; // first layer
let z: &&mut i32 = &y; // second layer
**z = 100; // Attempt to change `x`, gives compiler error.
println!("Value is: {}", z);
}
I'm getting the compiler error:
error[E0594]: cannot assign to `**z` which is behind a `&` reference
--> src/main.rs:5:5
|
4 | let z: &&mut i32 = &y; // second layer
| -- help: consider changing this to be a mutable reference: `&mut y`
5 | **z = 100; // Attempt to change `x`, gives compiler error.
| ^^^^^^^^^ `z` is a `&` reference, so the data it refers to cannot be written
In some way, this makes sense, as otherwise the compiler would not be able to prevent having multiple mutable access paths to the same variable.
However, when looking at the types, the semantics seem to be counter-intuitive:
- Variable
y
has type&mut i32
, or in plain English "A mutable reference to an integer". - Variable
z
has type&&mut i32
, or in plain English "An immutable reference to a mutable reference to an integer". - By dereferencing
z
once (i.e.*z
) I will get something of type&mut i32
, i.e. something of the same type asy
. However, dereferencing this again (i.e.**z
) gets me something of typei32
, but I am not allowed to mutate that integer.
In essence, the types of references in some sense lie to me, as they don't actually do what they claim they do. How should I read types of references properly in this case, or how else can I restore faith in that concept?
Testing with this sample:
fn main() {
let mut x = 42;
let y: &mut i32 = &mut x; // first layer
let m: &&mut i32 = &y; // second layer
let z: &&&mut i32 = &m; // third layer
compiler_builtin_deref_first_layer(*z);
}
fn compiler_builtin_deref_first_layer(v: &&mut i32) {
compiler_builtin_deref_second_layer(*v);
}
fn compiler_builtin_deref_second_layer(w: &mut i32) {
println!("Value is: {}", w);
}
The parameter types of those last two functions are correct. If I change any of those, the compiler will complain about mismatched types. However, if I compile the example as-is, I get this error:
error[E0596]: cannot borrow `**v` as mutable, as it is behind a `&` reference
Somehow, the call to compiler_builtin_deref_first_layer
seems to be okay, but the call to compiler_builtin_deref_second_layer
isn't. The compiler error talks about **v
, but I only see a *v
.