2015-11-25 9 views
8

Mam ENUM:Jak dopasować się do siebie w wyliczaniu?

enum Expr { 
    Lit(u32), 
    Var(Id), 
    Ass(Id, u32), 
    Add(u32, u32), 
    Sub(u32, u32), 
    Mul(u32, u32), 
} 

próbuję wdrożyć metodę:

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), 
     } 
    } 
} 

ale dostaję następujący błąd:

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

Bez gwiazdy, Otrzymuję również błąd:

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` 

Myślę, że rozumiem pierwszy błąd: staram się zrobić więcej, niż mi wolno z niezmiennym zapożyczonym self, ale nie jestem pewien co do drugiego błędu. Nie mam pojęcia, jak to zrobić właściwie.

+1

Można również skopiować 'Expr'. Lub skonsumuj go podczas oceny, jeśli i tak nie potrzebujesz go ponownie po ocenie. –

Odpowiedz

11

Na pytanie pierwsze, trzeba użyć słowa kluczowego ref, jak powiedział @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), 
     } 
    } 
} 

Korzystanie ref zapobiega wzór pasujący od zabierania własności id. Jak wspomniałeś, nie możesz wziąć wartości id z Expr, ponieważ masz niezmienną referencję. v, f i s nie mają tego problemu, ponieważ są u32, który implementuje Copy. Zamiast usuwać wartość, są one kopiowane, pozostawiając oryginał w miejscu.

nie wiem co rodzaj Env lub Id są lub definicje lookup i assign, więc może niektórzy clone() połączenia nie są konieczne.

Na drugie pytanie, to dlatego self jest typu &Expr, więc trzeba to & we wzorach:

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), 
     } 
    } 
} 

Obie formy dopasowywania są równoważne, ale *self jest bardziej idiomatyczne i wymaga mniej pisanie:)

Powiązane problemy