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:
impl Expr {
fn eval(&self, env: &mut Env) -> Result<u32, String> {
use Expr::*;
match *self {
Lit(l) => Ok(l),
Var(ref id) => env.lookup(id).ok_or_else(|| format!("undefined var {:?}", id)),
Ass(ref id, v) => {
env.assign(id.clone(), v);
Ok(v)
}
Add(f, s) => Ok(f + s),
Sub(f, s) => Ok(f - s),
Mul(f, s) => Ok(f * s),
}
}
}
Using ref
prevents the pattern matching from taking ownership of id
. As you mention, you are not allowed to take the value of id
out of the Expr
because you only have an immutable reference. v
, f
, and s
don't have this problem because they are u32
, which implements Copy
. Instead of taking the value out, they are copied, leaving the original in place.
I don't know what the Env
or Id
type are, or the definitions of lookup
and assign
, so perhaps some clone()
calls are not necessary.
For your second question, this is because self
is of type &Expr
, so you need to include &
in the patterns:
impl Expr {
fn eval(&self, env: &mut Env) -> Result<u32, String> {
use Expr::*;
match self {
&Lit(l) => Ok(l),
&Var(ref id) => env.lookup(id).ok_or_else(|| format!("undefined var {:?}", id)),
&Ass(ref id, v) => {
env.assign(id.clone(), v);
Ok(v)
}
&Add(f, s) => Ok(f + s),
&Sub(f, s) => Ok(f - s),
&Mul(f, s) => Ok(f * s),
}
}
}
Both forms of matching are equivalent, but *self
is more idiomatic and requires less typing :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With