2015-12-14 110 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,因为它有点短。没有更好的理由。