0

I have a Vec<Vec<T>> (I know it's not ideal; it's from a library). I want to look at pairs of Vecs in the outer vec and push to each of them, something like this:

let mut foo = vec![
    vec![1, 2, 3],
    vec![4, 5, 6],
    vec![7, 8, 9],
];

for i in foo.len() {
    let a = foo.get_mut(i - 1).unwrap();
    let b = foo.get_mut(i).unwrap(); // Does not work

    let val = 2; // Some computation based on contents of a & b

    a.push(val);
    b.insert(0, val);
}

Of course, this fails to compile:

error[E0499]: cannot borrow `foo` as mutable more than once at a time
  --> foo.rs:6:17
   |
5  |         let a = foo.get_mut(i - 1).unwrap();
   |                 --- first mutable borrow occurs here
6  |         let b = foo.get_mut(i).unwrap(); // Does not work
   |                 ^^^ second mutable borrow occurs here
...
10 |         a.push(val);
   |         - first borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.

It's a similar pattern to the std::slice::window() method, but as far as I can tell you can't get any mutable items in that.

Is there a way to do this that makes the borrow checker happy?

avandesa
  • 178
  • 1
  • 6

2 Answers2

2

In general, this kind of mutation of different parts of a single object at the same time requires unsafe. There really isn't a general way for the compiler to tell that you're really accessing disjoint parts of the object.

However, in this case, there's a simple encapsulation that should work for your usage. The slice method split_at_mut enables you to get mutable slices of two halves of a mutable slice.

let mut foo = vec![
    vec![1, 2, 3],
    vec![4, 5, 6],
    vec![7, 8, 9],
];

for i in 1..foo.len() {
    //   ^^^  note the change
    let (first_half, second_half) = foo.split_at_mut(i);

    // now `first_half` is `foo[0..i]`
    // `second_half` is `foo[i..]`
    let a = first_half.last_mut().unwrap();
    let b = second_half.first_mut().unwrap();

    let val = 2; // Some computation based on contents of a & b

    a.push(val);
    b.insert(0, val);
}

(playground)

You may be able to avoid this completely by holding off on the mutable borrow until you actually mutate the vectors.

let mut foo = vec![
    vec![1, 2, 3],
    vec![4, 5, 6],
    vec![7, 8, 9],
];

for i in 1..foo.len() {
    // this could equally be written
    // let a = &foo[i - 1];
    let a = foo.get(i - 1).unwrap();
    let b = foo.get(i).unwrap();

    // This probably doesn't need mutable access, right?
    let val = 2; // Some computation based on contents of a & b

    // now borrow again, but this time mutate.
    foo[i - 1].push(val);
    foo[i].insert(0, val);
}

(playground)

SCappella
  • 9,534
  • 1
  • 26
  • 35
  • Please search for existing questions with the answer you propose before answering. There's no need to duplicate this kind of common question and answer many times across Stack Overflow. – Shepmaster Nov 19 '19 at 15:00
1

You can use split_at_mut to get two disjoint mutable partitions of a slice. So you could do this:

let (a,b) = foo.split_at_mut(i);
let a = a.last_mut().unwrap();
let b = b.first_mut().unwrap();
Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • Please search for existing questions with the answer you propose before answering. There's no need to duplicate this kind of common question and answer many times across Stack Overflow. – Shepmaster Nov 19 '19 at 15:00