> In Rust it's also obvious because every = is a move.
False, depending on the presence of an explicit type annotation on the left-hand side, an = triggers either a move or a reborrow.If you assume = always moves you can just never use automatic reborrowing (do &mut * instead) and you'll loose nothing.
I don't think that's a very common pattern, fully optional and it can be just treated as another exception to the rule, just like Copy types. You don't have to manually write .copy() in some cases, and you don't have to manually write &mut* in some others. But that's what happens. Move is still done.
So that's total of two exceptions. Way easier to be tackled individually when the time comes than assuming = means something else, or something complex from the start.
> pub fn main() {
> let mut x = String::from("moo");
> let y = &mut x;
> let z = y;
> println!("{:?}", y)
> }
>
> pub fn main() {
> let mut x = String::from("moo");
> let y = &mut x;
> let z: &mut _ = y;
> println!("{:?}", y)
> }It's completely optional fearure. You don't have to rely on it. Like auto-insertion of semicolons in JS maybe it's better if you don't. Although likelihood of this biting you is way lower than in case of relying on semicolons autoinsertion.
My claim is that for most Rust users, understanding the borrow checker is limited to a few heuristics that seem to work for them 80% of the time, and throwing up their hands and declaring an approach unworkable the remaining 20% of the time. To a first approximation, no one can mentally model the borrow checker beyond extremely simple examples of 4-5 lines of code.