I have the following code which compiles fine
#[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()
}
}
But if I replace the Expression::Add arm with the commented out version, I get the following compiler error
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`.
Is there a reason we may match against the lone **x but not in a tuple like (**x, **y)? Is the former actually being converted or hiding some syntactic sugar? Is there a simpler way of writing this Add arm than with the two nested matches?
EDIT: I also see that there is a ref keyword, which is supposed to address something like this, but changing my tuple match expression to (ref **x, ref **y) gives a syntax error (error: expected expression, found keyword ref).