2

I'm trying to learn Rust's ownership and lifetimes in more detail, and I'm very confused by this piece of code:

let mut lst = vec![1, 2, 3];
let mut x = &mut 0;

for value in &mut lst {
    *value += 1;
    *x += 1;
    x = value;
}

*x += 1;
println!("{:?}", &lst);

From what I understand, Rust disallows having more than one mutable reference to any value, and a mutable reference to an element in a vector also borrows the vector itself. So it should not be possible to simultaneously have mutable references to two elements in a vector.

But in the code above, the body of the loop stores a mutable reference to an element in lst in x outside the loop. Then, in the next iteration, it takes another mutable reference to a different element in lst, giving me two mutable references to two elements in the list at once.

So my question is: Why is this allowed?

1
  • 1
    Not only can you get mutable references to two distinct elements at the same time. You can get mutable references to all elements at the same time: lst.iter_mut().collect::<Vec<_>>(). This works because each mutable reference from the iterator will be distinct. Much like you can simultaneously have mutable references to different fields in a struct. Commented Oct 12, 2021 at 19:13

2 Answers 2

8

While Rust does not allow you to have multiple mutable references to the same value, it does allow you to have mutable references to non-overlapping parts of the same value.

For example, you can split a &mut T into separate mutable references for each field, and the borrow checker will keep track of this for you:

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

let mut foo = Foo { x: 0, y : 0 };

let foo_mut = &mut foo;
let x = &mut foo_mut.x;
let y = &mut foo_mut.y;

*x = 1;
*y = 2;

println!("x = {:?}", x);     // 1
println!("y = {:?}", y);     // 2
println!("foo = {:?}", foo); // Foo { x: 1, y: 2 }

Similarly, you can split a mutable slice reference &mut [T] with methods like split_at_mut and split_first_mut, which both give you two non-overlapping mutable references to the slice.

In fact, iteration of a mutable slice can be implemented using split_first_mut:

let mut lst = vec![1, 2, 3];
let mut x = &mut 0;

let mut rest = &mut *lst;
while let Some((value, rest_)) = rest.split_first_mut() {
    rest = rest_;

    *value += 1;
    *x += 1;
    x = value;
}

*x += 1;
println!("{:?}", &lst);

So it's fine for the iterator of &mut [T] (and &mut Vec<T>) to give multiple mutable references that coexist, as long as those mutable references point to different parts of the vector and do not overlap.

Sign up to request clarification or add additional context in comments.

4 Comments

nice explanation :D
@Mark You're absolutely correct, thanks!
what about non-overlapping parts of a mutable slice?
@GuerlandoOCs Yes, you are allowed to have multiple mutable references to non-overlapping parts of a slice, and you can construct those in safe Rust by using for example split_at_mut.
1

In the end you do not hold a mut reference more than once,in x = value the reference is moved into x. It would be different if that line was first in the loop:

fn main() {
    let mut lst = vec![1, 2, 3];
    let mut x = &mut 0;

    for value in &mut lst {
        x = value;

        *value += 1;
        *x += 1;
    }

    *x += 1;
    println!("{:?}", &lst);
}

In where of course the compiler complains:

error[E0503]: cannot use `*value` because it was mutably borrowed
 --> src/main.rs:8:9
  |
6 |         x = value;
  |             ----- borrow of `*value` occurs here
7 | 
8 |         *value += 1;
  |         ^^^^^^^^^^^ use of borrowed `*value`
9 |         *x += 1;
  |         ------- borrow later used here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.