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 :)