Rust is my first language after Python, so I'm try to understand all the reference/pointer stuff by playing with and reading about it.
I don't understand difference between the cases below.
let mut val_a = 5;
println!("val_a is {}", val_a);
val_a = 10;
println!("Now val_a is {}", val_a);
let mut val_b = 5;
let val_b_ref = &mut val_b;
println!("val_b by ref is {}", val_b_ref);
// Can not call line below because of further mutation of val_b
// println!("val_b is {}", val_b);
*val_b_ref = 20;
println!("val_b by ref is {}", val_b_ref);
// Now val_b can be called since no mutation after that
println!("val_b is {}", val_b);
I do not understand why in first case I can print val_a
despite it being mutated after, while I cannot print val_b
when it's mutated via deref operator.
Rust disallows aliasing of mutable values. What this means is that there must be at most one name through which a value can be mutated at any given moment. An extant mutable reference creates a new name through which the value can be mutated, and so it "blocks" access to the original name as long as it's alive.
In the first example, there is exactly one name (val_a
). You can read from and write to the underlying value through this name.
In the second example, you have two names: val_b
and val_b_ref
. The commented-out line causes a compilation error because you can't access val_b
through that name because another name exists through which the value can be mutated (val_b_ref
). The lifetime of this other name must end before you can use val_b
again.
Because Rust implements non-lexical lifetimes for variables, val_b_ref
is considered dead on all lines after it is last used, which is why you can use val_b
again on the last line of the second example.