如何在嵌套匹配语句中多次访问可变向量?

时间:2018-01-18 20:30:27

标签: rust pattern-matching borrow-checker

我有以下代码:

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
        }
    }
}

编译器抱怨:

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

我理解问题是因为我有a的两个可变引用,但我找不到解决方案。

2 个答案:

答案 0 :(得分:2)

如果您愿意为第一场比赛的副本做出折衷,您可以这样做:

#[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
}

如果您的类型为Clone但不是Clone,则这也适用于Copy。另一种选择是使用问题评论中建议的split_at_mut()

答案 1 :(得分:0)

如果您使用夜间编译器,则可以使用

  • 功能slice_patterns以匹配切片
  • split_at_mut正如评论中所述

代码:

#![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
    }
}

此代码不具有超级可读性,因为所有内容都是参考,因为您需要详尽地介绍模式,但它符合您的要求。