我在结构上匹配
并且想使用匹配守卫。但是,该结构是可变的,匹配臂左侧的绑定(bind)变量似乎会导致单独借用。这随后会触发编译错误,因为当可变借用未完成时您不能进行第二次借用(可变或不可变)。
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
我目前的解决方法是在我的比赛之前复制计算比赛守卫的逻辑,然后我可以只使用 bool 值作为我的比赛守卫。这对于明显的代码重复问题并不令人满意:
fn do_a_thing(&mut self) {
let awesome = match *self {
Container(ref a) => a.is_awesome(),
};
match *self {
Container(..) if awesome => self.update(),
_ => {},
}
}
最佳答案
当 non-lexical lifetimes are enabled ,您的原始代码按原样工作。
在非词法生命周期之前
以安全的名义,Rust 禁止各种类型的事情,即使它们的特定情况可能有效。这就是一个这样的案例,您尝试做的事情不可能也永远不可能。
您已经创建了对 self
内容的引用,但随后您调用了 self.update()
,它需要对 self
的可变引用>。一种语言可以有效地内联update
,从而确定保持该引用有效是安全的,但是很容易证明基本概念并不总是适用于这个例子Rust 编译器为您避免的坏处:
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
}
如果这被允许编译,它会 panic ,因为 a
的目标,尽管它是一个不可变的引用,但在你的下面发生了变化,这是不允许它做的事情。
C++ 模板的无忧无虑的心态就是尝试一些可能有效或可能无效的事情的例子;对他们来说,一个函数内部的深层变化很可能会破坏它的用户,以至于他们不再编译。 Rust 决定不走那条路,因此将每种方法都视为强大的隔离屏障。对函数主体的任何更改都不会导致方法外部的代码停止编译。
当您在 self
上调用 &mut self
请求方法时,您不能对 self
内的任何内容有任何引用,无论是可变的还是其他方式。
关于pattern-matching - 在匹配可变引用时如何在匹配臂中绑定(bind)变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29688753/