Mutability

mut param: mut type

The below snippet confused me when I first saw it:

fn some_function(mut v: &mut Vec<usize>) -> {
    // redacted -- not important
}

It confused me, because I had to ask the question, what is the difference between mut v and &mut Vec<usize>? And when to use which?

It will be simple at first, but there will be a harder question in the end. Even if you are comfortable with mutability in Rust, I still suggest reading through as a refresher.


Basic Stuff

Ok, let’s start with &mut Vec<usize> (mut keyword is describing the type, not the variable/parameter):

it basically allow us to mutate the content of the v (which is the type)

fn some_function(v: &mut Vec<usize>) {
    v[1] = 10; // we can modify the values in the vector
    v.push(4); // we can modify the vector itself
}


fn main() {
    let mut vector = vec![1,2,3];
    some_function(&mut a);
    for num in vector {
        println!("{num}");
    }
}

But v: &mut Vec<usize> does not allow us to modify the v itself. We cannot reassign another value to v.

(you can ignore the lifetimes in the below example, it is just to make the compiler happy)

fn some_function<'a>(v1: &'a mut Vec<usize>, v2: &'a mut Vec<usize>) {
    v1 = v2; // error[E0384]: cannot assign to immutable argument `v`
}


fn main() {
    let mut vector = vec![1,2,3];
    let mut another_vec = vec![1,2,3];
    some_function(&mut vector, &mut another_vec);
}

If you want to see a simpler example on why we cannot reassign, here you go:

fn some_function(num1: usize, num2: usize) {
    num1 = num2; // error[E0384]: cannot assign to immutable argument `num1`
}


fn main() {
    some_function(1,2);
}

So, to be able to reassign or override the value of our variables, we need the mut keyword.

fn some_function(mut num1: usize, num2: usize) {
    num1 = num2; // now works
}


fn main() {
    some_function(1,2);
}

Recap

fn some_function(mut v: &mut Vec<usize>) -> {
    // redacted -- not important
}
  • mut v: allows us to overwrite the value of v
  • &mut Vec<usize>: allows us to modify the content of the type (in this case, Vec<usize>)

Things will start get weird soon

Can we modify the vector itself if mut keyword is not present in the type? See below:

fn some_function(mut v1: &Vec<usize>) {
    v1.push(5);
}


fn main() {
    let mut vector = vec![1,2,3];
    some_function(&vector);
}

No! As expected, we got the following error for the line:

v1.push(5); // error[E0596]: cannot borrow `*v1` as mutable, as it is behind a `&` reference

Now, it should be crystal clear. But one last example, will below code work?

fn some_function(mut v1: Vec<usize>) {
    v1.push(5);
}


fn main() {
    let mut vector = vec![1,2,3];
    some_function(vector);
}

Surprisingly it works! But how? In order to modify the vector itself, we have provide mut keyword for the type, not the variable. On top of that, compiler tells us we can remove mut from the line:

let mut vector = vec![1,2,3]

Let’s do it:

fn some_function(mut v1: Vec<usize>) {
    v1.push(5);
}


fn main() {
    let vector = vec![1,2,3];
    some_function(vector);
}

And it still works! Let’s remove the mut from variable as well:

fn some_function(v1: Vec<usize>) {
    v1.push(5);
}


fn main() {
    let vector = vec![1,2,3];
    some_function(vector);
}

Now it doesn’t work… So, seems like mut v1 is not only for overwriting the value of v1, but also for manipulating the content of it?


Ownership and mutability

Here is the catch: mut v1 means, we can modify anything that v1 owns.

The above example worked:

fn some_function(mut v1: Vec<usize>) {
    v1.push(5);
}


fn main() {
    let vector = vec![1,2,3];
    some_function(vector);
}

Because v1 owns Vec<usize>, it is not a reference to a vector anymore. And since we can mutate v1, we can also mutate anything that v1 owns. Notice that, this encapsulates reassigning the value of v1.

Here is another example with structs:

struct Point {
    x: i32,
    y: i32,
}


fn main() {
    let mut p = Point { x: 0, y: 0 };
    p.x = 1;


    println!("{}, {}", p.x, p.y);
}

In here, the mut keyword is describing the variable p, not the type Point. Yet, we are able to modify the inner parts of the type. Why? Because of the same reason: p owns the Point.

So, again: mut v1 means, we can modify anything that v1 owns.

Coming back to this example from before:

fn some_function(mut v1: &Vec<usize>) {
    v1.push(5);

    // assigning another reference to `v1` will work here
}


fn main() {
    let mut vector = vec![1,2,3];
    some_function(&vector);
}

v1 does NOT own the Vec<usize> but it owns the reference to the vector. So, we can modify the reference itself (pointing towards another reference), but we cannot modify the content of what the reference points to.


Summary

  • &mut Type: modify the content of the Type
  • mut v: modify anything that v owns.

alt text