Reputation: 366
I am trying to iterate over an array, mutably borrowing its elements one by one. In each iteration, I want to use the results from the previous one. I wrote the code like the one below:
fn main() {
let mut arr: [Vec<u32>; 3] = [vec![1, 2, 3], Vec::new(), Vec::new()];
for i in 1..3usize {
let prev_vec: &Vec<u32> = &arr[i - 1];
for prev_num in prev_vec {
arr[i].push(prev_num * 2);
}
}
dbg!(arr);
}
However, it seems that in the line let prev_vec: &Vec<u32> = &arr[i - 1];
instead of borrowing only the vector, the whole array gets marked as borrowed. The compiler errors is
--> example.rs:6:13
|
4 | let prev_vec: &Vec<u32> = &arr[i - 1];
| ----------- immutable borrow occurs here
5 | for prev_num in prev_vec {
| -------- immutable borrow later used here
6 | arr[i].push(prev_num * 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Why does the borrow checker assume the whole array is borrowed? How can I rewrite this code, so it is accepted by the compiler?
Upvotes: 2
Views: 545
Reputation: 30577
Indexing operations borrow the whole container - you can see that from the definition of the Index
and IndexMut
traits:
fn index(&self, index: Idx) -> &Self::Output;
The reason for this is that otherwise you could do something to the array that would invalidate the reference to the vec element. For example:
let e1 = arr[1];
arr.push(vec![9,8,7]);
Pushing something onto arr
could result in it being re-allocated to a different area of memory, to accomodate the new element. That would mean e1
would be left pointing to nothing.
You can work around that using the split_at_mut
method:
fn main() {
let mut arr: [Vec<u32>; 3] = [vec![1, 2, 3], Vec::new(), Vec::new()];
for i in 1..3usize {
let (prev,curr) = arr.split_at_mut(i);
let prev_arr = prev.last().unwrap();
let this_arr = curr.first_mut().unwrap();
for prev_num in prev_arr {
this_arr.push(prev_num * 2);
}
}
dbg!(arr);
}
split_at_mut
takes a slice and gives you back two mutable sub-slices.
Upvotes: 2