Mut on left or right of equal sign

What is the difference between

let x = 0;
let mut y = &x;

and

let x = 0;
let y = &mut x;

or even this

let x = 0;
let mut y = &mut x;

The first option is an immutable reference, but you can change which value it points at. The value behind the reference itself is immutable and can't be modified.

The second option is a mutable reference, but you can't change which value it points at. (And some mutable operations on the value itself also fail.)

The third option is a mutable reference, and you can change which value the reference points at.

Can you explain a bit more about the second. What do you mean exactly by cant change the value it points at and what are some examples about operations on the value that may fail?

I mean that this does not compile unless you add a mut on the let y line.

fn main() {
    let mut x1 = 0;
    let mut x2 = 10;
    
    let y = &mut x1;
    y = &mut x2;
    
    *y = 20;
    
    // should print 0, 20
    println!("{}, {}", x1, x2);
}

Sometimes if you try to modify the target of the reference without changing what the target is, you still need y to be marked mut. I don't know the exact rules for when you can modify the target without mut on y.

Try changing them and you'll learn more about what they do.

For example, try this:

let mut z = 100;

let x = 0;
let mut y = &x;
*y = z;
y = &z;

let x = 0;
let y = &mut x;
*y = z;
y = &mut z;

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dfc0af899bcf4c47f5c366d7b4e57607

1 Like

In this case, isnt the line y = &mut x2; the problem? You cannot reassign y since it is not mut.

Yes, that's correct.

From a higher perspective, mut on the left (mut on a binding) is largely a lint-like feature. It doesn't change the type of the variable, and you can always just rebind variables you own.

let x = String::new();
// This is fine, it's still a `String`, you're just allowed to mutate it now
let mut x = x;
// Still a `String` but back to not being able to mutate it.
let x = x;

Where as &T and &mut T are two different types which behave quite differently; you can also coerce from a &mut T to a &T but never the other way around.

3 Likes