我有以下代码,可以正常编译
#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
Const(i32),
Neg(Box<Expression>),
Add(Box<Expression>, Box<Expression>),
}
fn simplify(expr: &Expression) -> Expression {
match expr {
Expression::Neg(x) => match **x {
Expression::Const(n) => Expression::Const(-n),
_ => expr.clone()
},
// GIVES ERROR
// Expression::Add(x, y) => match (**x, **y) {
// (Expression::Const(n), Expression::Const(m)) => Expression::Const(n + m),
// _ => expr.clone()
// },
Expression::Add(x, y) => match **x {
Expression::Const(n) => match **y {
Expression::Const(m) => Expression::Const(n + m),
_ => expr.clone()
}
_ => expr.clone()
}
_ => expr.clone()
}
}
但是,如果我用注释掉的版本替换
Expression::Add
臂,则会出现以下编译器错误
error[E0507]: cannot move out of `**x` which is behind a shared reference
--> src/lib.rs:21:41
|
21 | Expression::Add(x, y) => match (**x, **y) {
| ^^^ move occurs because `**x` has type `Expression`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `**y` which is behind a shared reference
--> src/lib.rs:21:46
|
21 | Expression::Add(x, y) => match (**x, **y) {
| ^^^ move occurs because `**y` has type `Expression`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0507`.
是否有理由我们可以与单独的
**x
匹配,但不能在像 (**x, **y)
这样的元组中匹配?前者实际上是被转换还是隐藏了一些语法糖?有没有比两个嵌套匹配更简单的方法来编写这个 Add
臂?
编辑:我还看到有一个
ref
关键字,它应该解决类似的问题,但是将我的元组匹配表达式更改为 (ref **x, ref **y)
会产生语法错误(error: expected expression, found keyword ref
)。
TL;DR: 与
(&**x, &**y)
比赛。
这里发生的事情很有趣。 TL;DR 是:当您
match v {}
时,您不会阅读 v
。您为 v
创建了一个 地方。
A place 是我们可以阅读的东西。或者写信给。或者什么也不做。重要的是,仅仅创造场所并不涉及这样的操作。您可以稍后读/写它,但是当您创建它时,它只是一个地方。
在您的
match
中,x
和 y
的类型为 &Box<Expression>
。当我们match **x
时,我们不读x
。因此,我们也不会移动**x
。我们所做的是为**x
创造一个地方。然后我们将这个地方与 Expression::Const(n)
进行匹配。现在我们读取 x
并从中提取 n
。但是 n
是 i32
- Copy
- 所以这很好。
相反,当您使用元组
(**x, **y)
时,由于您不直接与 **x
和 **y
匹配,因此您确实会读取它们。因为你读了它们,而它们不是 Copy
(Expression
),所以你就离开了它们。现在这是一个错误,因为您无法移出共享引用。您之后匹配它们,但它们已经移动了。
你可以试试
match(x.as_ref(),y.as_ref())