Rust question : Cannot borrow parts of tuple mutably and immutably when tuple is inside a vector

Viewed 101

I have tried to execute the following code, but it doesn't compile because "a vector cannot be borrowed as mutable because it is also borrowed as immutable".

The problem is that I don't see how error message is relevant. I am borrowing immutably array[1].1 and mutably array[1].0 which don't overlap.

Isn't borrow checker smart enough to see that there is no conflict and non-overlapped parts of tuples are accessed?

fn main() {
  //everything is ok when tuple is alone
  let mut pair : (usize, Vec<usize>) = (0, Vec::new());
  println!("{} {:?}", &pair.0, &mut pair.1);

  let mut array : Vec<(usize, Vec<usize>)> 
      = vec![(1, Vec::new()), (2, Vec::new())];
  //everything works till here
  // but the rest doesn't...
  println!("{} {:?}", &array[1].0, &mut array[1].1);
}

I am confused : why can I borrow parts of a single tuple mutably and immutably, but cannot do it when tuple is inside a vector. Is it related to splitting borrows described in Rustonomicon?

And finally, the most important : is there a way to fix this code without separating a vector of tuples into 2 vectors?

While a quick answer to the last question is enough for me, I would appreciate a bit more explanation and also answers to my other questions. And if you have a more idiomatic Rust solution for such problem, that would be great too :)

Thanks in advance for taking your time to help me.

1 Answers

This fails because the indexing operation tries to borrow array mutably and immutably at the same time, which isn't allowed.

However, you can borrow different parts of a value even mutably at the same time (a "splitting borrow"), but to do this Rust has to know that they are part of the same value. It can't figure this out when you index array twice. (Nothing requires that Index and IndexMut return a reference to the same value, nor that they will do so given the same index when called twice, nor that IndexMut won't modify any state.)

You can accomplish this by borrowing a particular item once, then reborrowing parts of it:

// Borrow mutably from the array once.
let item1 = &mut array[1];

// Reborrow different parts of the item, splitting the mutable borrow above
// into two borrows.
println!("{} {:?}", &item1.0, &mut item1.1);

(Playground)

Related