在匹配可变引用时如何在匹配臂中绑定变量?
How can I bind a variable in a match arm when matching on a mutable reference?
我正在 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(),
_ => {},
}
}
当 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
}
如果这被允许编译,它会恐慌,因为 a
的目标,尽管它是一个不可变的引用,但在你的下面发生了变化,这显然是不允许的。
C++ 模板的无忧无虑的心态是尝试可能有效或可能无效的方法的一个例子;对他们来说,一个函数内部的深层变化很可能会破坏它的用户,以至于他们不再编译。 Rust 决定不走那条路,因此将每种方法都视为强大的隔离屏障。对函数体的任何更改都不会导致方法外的代码停止编译。
当您在 self
.
上调用 &mut self
请求方法时,您不能对 self
中的任何内容有任何引用,无论是可变的还是其他方式。
我正在 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(),
_ => {},
}
}
当 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
}
如果这被允许编译,它会恐慌,因为 a
的目标,尽管它是一个不可变的引用,但在你的下面发生了变化,这显然是不允许的。
C++ 模板的无忧无虑的心态是尝试可能有效或可能无效的方法的一个例子;对他们来说,一个函数内部的深层变化很可能会破坏它的用户,以至于他们不再编译。 Rust 决定不走那条路,因此将每种方法都视为强大的隔离屏障。对函数体的任何更改都不会导致方法外的代码停止编译。
当您在 self
.
&mut self
请求方法时,您不能对 self
中的任何内容有任何引用,无论是可变的还是其他方式。