2015-12-14 124 views
2

我努力學習鏽借來的HashMap,所以忍耐一下,如果我的路要走:-)模式匹配在包含枚舉

我有枚舉插入到一個HashMap,並使用String個程序作爲關鍵。我試圖匹配HashMap的內容。問題是我無法弄清楚如何在eval_output函數中獲得正確的借款,參考和類型。 eval_output函數應該如何正確處理對HashMap的引用?有沒有我可以閱讀的優秀文件來了解更多關於這個特定主題的內容?

use std::prelude::*; 
use std::collections::HashMap; 

enum Op { 
    Not(String), 
    Value(u16), 
} 

fn eval_output(output: &str, outputs: &HashMap<String, Op>) -> u16 { 
    match outputs.get(output) { 
     Some(&op) => { 
      match op { 
       Op::Not(input) => return eval_output(input.as_str(), outputs), 
       Op::Value(value) => return value, 
      } 
     } 
     None => panic!("Did not find input for wire {}", output), 
    } 
} 

fn main() { 
    let mut outputs = HashMap::new(); 

    outputs.insert(String::from("x"), Op::Value(17)); 
    outputs.insert(String::from("a"), Op::Not(String::from("x"))); 

    println!("Calculated output is {}", eval_output("a", &outputs)); 
} 

回答

4

回顧一下編譯器錯誤消息是:

error: cannot move out of borrowed content [E0507] 
     Some(&op) => { 
       ^~~ 
note: attempting to move value to here 
     Some(&op) => { 
       ^~ 
help: to prevent the move, use `ref op` or `ref mut op` to capture value by reference 

雖然技術上是正確的,使用Some(ref op)將是一個有點傻,作爲op類型將被雙引用(&&Op)。相反,我們只需刪除&並擁有Some(op)

這是咬的人,因爲得到它的權利,你必須熟悉兩個模式匹配引用,再加上鏽的嚴格檢查借一個常見的錯誤。當你有Some(&op),上面寫着

Match an Option that is the variant Some . The Some must contain a reference to a value. The referred-to thing should be moved out of where it is and placed into op .

當模式匹配,這兩個關鍵字refmut可以發揮作用。這些是而不是模式匹配,但相反,它們控制值綁定的變量名稱。它們是&mut的類似物。

這導致我們的下一個錯誤:

error: mismatched types: 
expected `&Op`, 
    found `Op` 

    Op::Not(input) => return eval_output(input.as_str(), outputs), 
    ^~~~~~~~~~~~~~ 

它更希望做match *some_reference,在可能的情況,但在這種情況下,你不能。所以我們需要更新模式以匹配對Op - &Op的引用。看看接下來會發生什麼樣的錯誤...

error: cannot move out of borrowed content [E0507] 
    &Op::Not(input) => return eval_output(input.as_str(), outputs), 
    ^~~~~~~~~~~~~~~ 

這是我們以前的朋友。這一次,我們將遵循編譯器的建議,並將其更改爲ref input。多一點變化,我們就會明白:

use std::collections::HashMap; 

enum Op { 
    Not(String), 
    Value(u16), 
} 

fn eval_output(output: &str, outputs: &HashMap<String, Op>) -> u16 { 
    match outputs.get(output) { 
     Some(op) => { 
      match op { 
       &Op::Not(ref input) => eval_output(input, outputs), 
       &Op::Value(value) => value, 
      } 
     } 
     None => panic!("Did not find input for wire {}", output), 
    } 
} 

fn main() { 
    let mut outputs = HashMap::new(); 

    outputs.insert("x".into(), Op::Value(17)); 
    outputs.insert("a".into(), Op::Not("x".into())); 

    println!("Calculated output is {}", eval_output("a", &outputs)); 
} 
  1. 有沒有必要use std::prelude::*; - 編譯器插入自動。

  2. as_str不存在於穩定的鏽中。對String&String)的引用可以使用deref強制來像字符串片段(&str)那樣操作。

  3. 我用into而不是String::from,因爲它有點短。沒有更好的理由。