简体   繁体   中英

Multiple mutable references in a loop

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?

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM