如何模式匹配包含 &mut 枚举的元组并在匹配臂中使用枚举?
How can I pattern match a tuple containing a &mut enum and use the enum in the match arm?
下面的代码如何编译?看起来非常安全,但无法让编译器相信它是安全的。
版本匹配*self
报错:cannot move out of borrowed content
匹配
行
匹配self
的版本给出:use of moved value: *self
enum Foo {
Foo1(u32),
Foo2(i16),
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
match (*self, y) {
(Foo::Foo1(ref mut a), b) if (b == 5) => {
print!("is five");
*a = b + 42;
(b, self)
}
(Foo::Foo2(ref mut a), b) if (b == 5) => {
print!("is five");
*a = (b + 42) as i16;
(*a * b, self)
}
_ => {
print!("is not five!");
(y, self)
}
}
}
}
我觉得我需要像下面这样的匹配臂,但它似乎不是有效的语法:
(ref mut f @ Foo::Foo1, b) if (b == 5) => {
print!("is five");
f.0 = b + 42;
(b, f)
}
error[E0532]: expected unit struct/variant or constant, found tuple variant `Foo::Foo1`
--> src/main.rs:24:30
|
24 | (ref mut f @ Foo::Foo1, b) if (b == 5) => {
| ^^^^^^^^^ not a unit struct/variant or constant
不,这不安全。您正试图在匹配臂中引入 可变别名 。可变引用 a
指向与 self
相同的值。可以更改 self
(例如 *self = Foo::Foo1(99)
),这会使 a
无效,因此不允许使用此代码。
相反,在 match
语句中可变地重新借用 self
并使其 return 成为元组的第一个值。由于此值没有对 self
的引用,因此您可以 return self
使用 match
:
的结果
enum Foo {
Foo1(u32),
Foo2(u32), // changed so I don't have to figure out what casting you meant
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
let next = match (&mut *self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
b
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
*a * b
}
_ => y,
};
(next, self)
}
}
然而,returning self
在这里是毫无意义的。来电者已经有一个&mut Foo
,所以你不需要"give it back"。这允许简化为:
impl Foo {
fn bar(&mut self, y: u32) -> u32 {
match (self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
b
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
*a * b
}
_ => y,
}
}
}
I would still say it is a safe operation, although the compiler may not be able to understand that
有了non-lexical lifetimes,借用检查器变得更加智能。添加显式重新借用的原始代码编译:
#![feature(nll)]
enum Foo {
Foo1(u32),
Foo2(u32), // changed so I don't have to figure out what casting you meant
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
match (&mut *self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
(b, self)
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
(*a * b, self)
}
_ => (y, self),
}
}
}
另请参阅:
下面的代码如何编译?看起来非常安全,但无法让编译器相信它是安全的。
版本匹配*self
报错:cannot move out of borrowed content
匹配
匹配self
的版本给出:use of moved value: *self
enum Foo {
Foo1(u32),
Foo2(i16),
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
match (*self, y) {
(Foo::Foo1(ref mut a), b) if (b == 5) => {
print!("is five");
*a = b + 42;
(b, self)
}
(Foo::Foo2(ref mut a), b) if (b == 5) => {
print!("is five");
*a = (b + 42) as i16;
(*a * b, self)
}
_ => {
print!("is not five!");
(y, self)
}
}
}
}
我觉得我需要像下面这样的匹配臂,但它似乎不是有效的语法:
(ref mut f @ Foo::Foo1, b) if (b == 5) => {
print!("is five");
f.0 = b + 42;
(b, f)
}
error[E0532]: expected unit struct/variant or constant, found tuple variant `Foo::Foo1`
--> src/main.rs:24:30
|
24 | (ref mut f @ Foo::Foo1, b) if (b == 5) => {
| ^^^^^^^^^ not a unit struct/variant or constant
不,这不安全。您正试图在匹配臂中引入 可变别名 。可变引用 a
指向与 self
相同的值。可以更改 self
(例如 *self = Foo::Foo1(99)
),这会使 a
无效,因此不允许使用此代码。
相反,在 match
语句中可变地重新借用 self
并使其 return 成为元组的第一个值。由于此值没有对 self
的引用,因此您可以 return self
使用 match
:
enum Foo {
Foo1(u32),
Foo2(u32), // changed so I don't have to figure out what casting you meant
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
let next = match (&mut *self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
b
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
*a * b
}
_ => y,
};
(next, self)
}
}
然而,returning self
在这里是毫无意义的。来电者已经有一个&mut Foo
,所以你不需要"give it back"。这允许简化为:
impl Foo {
fn bar(&mut self, y: u32) -> u32 {
match (self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
b
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
*a * b
}
_ => y,
}
}
}
I would still say it is a safe operation, although the compiler may not be able to understand that
有了non-lexical lifetimes,借用检查器变得更加智能。添加显式重新借用的原始代码编译:
#![feature(nll)]
enum Foo {
Foo1(u32),
Foo2(u32), // changed so I don't have to figure out what casting you meant
}
impl Foo {
fn bar(&mut self, y: u32) -> (u32, &mut Foo) {
match (&mut *self, y) {
(Foo::Foo1(a), b @ 5) => {
*a = b + 42;
(b, self)
}
(Foo::Foo2(a), b @ 5) => {
*a = b + 42;
(*a * b, self)
}
_ => (y, self),
}
}
}
另请参阅: