我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(),
_ => {},
}
}
答案 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}}内的任何内容都不能有任何引用,可变或其他内容。