I have an enum:
enum Expr {
Lit(u32),
Var(Id),
Ass(Id, u32),
Add(u32, u32),
Sub(u32, u32),
Mul(u32, u32),
}
I'm trying to implement a method:
impl Expr {
fn eval(&self, env: &mut Env) -> Result<u32, String> {
use Expr::*;
match *self {
Lit(l) => Ok(l),
Var(id) => env.lookup(&id).ok_or_else(|| format!("undefined var {:?}", id)),
Ass(id, v) => {
env.assign(id, v);
Ok(v)
}
Add(f, s) => Ok(f + s),
Sub(f, s) => Ok(f - s),
Mul(f, s) => Ok(f * s),
}
}
}
but I'm getting the following error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:25:15
|
25 | match *self {
| ^^^^^ cannot move out of borrowed content
26 | Lit(l) => Ok(l),
27 | Var(id) => env.lookup(&id).ok_or_else(|| format!("undefined var {:?}", id)),
| -- hint: to prevent move, use `ref id` or `ref mut id`
28 | Ass(id, v) => {
| -- ...and here (use `ref id` or `ref mut id`)
Without the star, I'm also getting an error:
error[E0308]: mismatched types
--> src/main.rs:25:17
|
25 | Lit(l) => Ok(l),
| ^^^^^^ expected &Expr, found enum `Expr`
|
= note: expected type `&Expr`
= note: found type `Expr`
I think I understand the first error: I'm trying to do more than I'm allowed with the (immutable) borrowed self
, but I'm not really sure about the second error. I have no idea how to do this properly.
For the first question, you need to use the
ref
keyword, as said by @Adrian:Using
ref
prevents the pattern matching from taking ownership ofid
. As you mention, you are not allowed to take the value ofid
out of theExpr
because you only have an immutable reference.v
,f
, ands
don't have this problem because they areu32
, which implementsCopy
. Instead of taking the value out, they are copied, leaving the original in place.I don't know what the
Env
orId
type are, or the definitions oflookup
andassign
, so perhaps someclone()
calls are not necessary.For your second question, this is because
self
is of type&Expr
, so you need to include&
in the patterns:Both forms of matching are equivalent, but
*self
is more idiomatic and requires less typing :)