在借用的包含枚举的HashMap上进行模式匹配

时间:2015-12-14 21:27:19

标签: enums rust

我正在努力学习Rust,所以如果我离开的话,请耐心等待: - )

我有一个程序可以将枚举插入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));
}

1 个答案:

答案 0 :(得分:5)

查看编译器错误消息:

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)

这是一个常常让人感到困惑的错误,因为要做到正确,你必须熟悉模式匹配引用,以及Rust的严格要求借用检查员。如果你有Some(&op),那就说

  

匹配Option变体SomeSome必须包含对值的引用。引用的东西应该移出它的位置并放入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并不存在于稳定的Rust中。对String&String)的引用可以使用 deref强制来充当字符串切片(&str)。

  3. 我使用into代替String::from,因为它有点短。没有更好的理由。