0

I have the following code:

enum T {
    A(bool),
    B(u8),
}

fn main() {
    let mut a = vec![T::A(true), T::B(42)];
    match a[0] {
        T::A(value) => println!("A: {}", value),
        T::B(ref mut b) => {
            match a[1] {
                T::A(value) => println!("One more A: {}", value),
                T::B(ref mut value) => *value += 1,
            }
            *b += 1
        }
    }
}

The compiler complains:

error[E0499]: cannot borrow `a` as mutable more than once at a time
  --> src/main.rs:11:19
   |
8  |     match a[0] {
   |           - first mutable borrow occurs here
...
11 |             match a[1] {
   |                   ^ second mutable borrow occurs here
...
17 |     }
   |     - first borrow ends here

I understand that the problem is because I have two mutable references to a, but I cannot find the solution.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Count Zero
  • 495
  • 6
  • 15
  • Probably a duplicate of [How to get mutable references to two array elements at the same time?](https://stackoverflow.com/q/30073684/155423) – Shepmaster Jan 18 '18 at 21:09
  • Unfortunately, using split_at_mut() method, as suggest here https://stackoverflow.com/questions/30073684/how-to-get-mutable-references-to-two-array-elements-at-the-same-time didn't help. I changed this line: `match a[1] {` to this: `let (left, right) = a.split_at_mut(1); match right[0] {` – Count Zero Jan 18 '18 at 21:38
  • You have to do it beforehand: https://play.rust-lang.org/?gist=dedc3a423709198dc059a12684cb1bfd&version=nightly – Shepmaster Jan 18 '18 at 21:40
  • In my code I determine the index that is used in second match just before this match. How to do this? – Count Zero Jan 18 '18 at 21:52
  • Split the original array into 3 parts: before `a[x]`, `a[x]`, and after `a[x]`. The first match will match on `a[x]` and then the second match can use the other two pieces. – Shepmaster Jan 18 '18 at 22:27
  • I still don't understand your idea, could you please give an example? – Count Zero Jan 19 '18 at 10:40

2 Answers2

2

If you are willing to make the trade off of having a copy for the first match, you can do something like this:

#[derive(Debug, Copy, Clone)]
enum T {
    A(bool),
    B(u8),
}

fn main() {
    let mut a = vec![T::A(true), T::B(42)];
    let first = a[0]; // make a copy
    match first {
        // match on the copy
        T::A(value) => println!("A: {}", value),
        T::B(b) => {
            match a[1] {
                T::A(value) => println!("One more A: {}", value),
                T::B(ref mut value) => *value += 1,
            }
            a[0] = T::B(b + 1) // then update the vector
        }
    }
    println!("{:?}", a); // the original didn't get split
}

This should also work with Clone if your types are Clone but not Copy. The other option is to use split_at_mut() as suggested in the question comments.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Daniel Wilkins
  • 447
  • 4
  • 7
0

If you use the nightly compiler, you can use

  • the feature slice_patterns to match against slices
  • split_at_mut as suggested in comments

Code:

#![feature(slice_patterns)]

enum T {
    A(bool),
    B(u8),
}

fn main() {
    let mut a = vec![T::A(true), T::B(42)];
    match a.split_at_mut(0) {
        (&mut [T::A(value)], _) => println!("A: {}", value),
        (&mut [T::B(ref mut b)], ref mut rest) => {
            match *rest {
                &mut [T::A(value)] => println!("One more A: {}", value),
                &mut [T::B(ref mut value)] => *value += 1,
                _ => (), // mandatory, because we match against slice
            }
            *b += 1
        }
        _ => (), // mandatory, because we match against slice
    }
}

This code is not super readable because everything is a reference and because you need to exhaustively cover the patterns but it fulfills your requirements.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Boiethios
  • 38,438
  • 19
  • 134
  • 183