在匹配可变引用时如何绑定匹配臂中的变量?

时间:2015-04-17 01:38:00

标签: pattern-matching rust

match在一个结构上,并希望使用一个匹配守卫。但是,结构是可变的,并且匹配臂左侧的绑定变量似乎导致单独的借位。这会触发编译错误,因为在可变借入尚未完成的情况下,您无法进行第二次借用(可变或不可变)。

struct A(u8);

impl A {
    fn is_awesome(&self) -> bool { true }
}

struct Container(A);

impl Container {
    fn update(&mut self) {}

    fn do_a_thing(&mut self) {
        match *self {
            Container(ref a) if a.is_awesome() => self.update(),
            _ => {},
        }
    }
}

fn main() {}
error[E0502]: cannot borrow `*self` as mutable because `self.0` is also borrowed as immutable
  --> src/main.rs:14:51
   |
14 |             Container(ref a) if a.is_awesome() => self.update(),
   |                       -----                       ^^^^ mutable borrow occurs here
   |                       |
   |                       immutable borrow occurs here
15 |             _ => {},
16 |         }
   |         - immutable borrow ends here

我目前的解决方法是复制逻辑以在匹配之前计算匹配防护,然后我可以使用布尔值作为我的匹配防护。对于明显的代码重复问题,这并不令人满意:

fn do_a_thing(&mut self) {
    let awesome = match *self {
        Container(ref a) => a.is_awesome(),
    };

    match *self {
        Container(..) if awesome => self.update(),
        _ => {},
    }
}

1 个答案:

答案 0 :(得分:4)

non-lexical lifetimes are enabled时,原始代码按原样运行。

在非词汇生命期之前

以安全的名义,Rust禁止各种类型的东西,即使它们的具体情况可能有效。这是一个这样的情况,你要做的不是也永远不可能。

您已创建对self内容的引用,但之后您调用self.update(),该self需要对update进行可变引用。语言可以有效地内联struct A(u8); struct Container(A); impl Container { fn update(&mut self) { self.0 = A(0); } fn do_a_thing(&mut self) { let a = &self.0; let before = a.0; self.update(); assert_eq!(before, a.0); } } fn main() { Container(A(1)).do_a_thing(); // Panic: 1 != 0 } ,从而确定将该引用保持活着是安全的,但是很容易证明基本概念并不总是适用于这个不良的例子。 Rust编译器可以让您免于:

a

如果允许编译,那就会引起恐慌,因为self的目标,尽管它是一个不可改变的引用,但在你下面发生了变化,显然绝不允许这样做。

C ++模板的快乐 - 幸运心态是尝试可能会或可能不会起作用的一个例子;它们很可能会在函数内部深处发生变化,从而破坏其用户,使其不再编译。 Rust决定不再走这条路,因此将每种方法视为强大的隔离屏障。对函数体的更改不会导致方法之外的代码停止编译。

&mut self上调用self请求方法时,{{1}}内的任何内容都不能有任何引用,可变或其他内容。