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

Kot*_*tte 3 enums rust

我正在尝试学习Rust,所以如果我走的话请忍受:-)

我有一个程序,将枚举插入到HashMap,并使用Strings作为键。我正在尝试匹配的内容HashMap。问题是我无法弄清楚如何在eval_output函数中获得正确的借用,引用和类型。该eval_output函数应如何正确处理对a的引用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));
}
Run Code Online (Sandbox Code Playgroud)

She*_*ter 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
Run Code Online (Sandbox Code Playgroud)

尽管从技术上讲是正确的,但使用起来Some(ref op)有点愚蠢,因为类型op会是双引用(&&Op)。相反,我们只需删除&和即可Some(op)。

这是一个困扰人们的常见错误,因为要正确使用它,您必须熟悉模式匹配和引用,再加上Rust严格的借位检查器。当你有的时候Some(&op),那说

匹配的Option是变体Some。在Some必须包含的值的参考。所指事物应从其所在位置移出并放入op。

模式匹配时,这两个关键字ref和mut可以起作用。它们不是模式匹配的,而是它们控制如何将值绑定到变量名。它们是&和的类似物mut。

这导致我们进入下一个错误:

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

    Op::Not(input) => return eval_output(input.as_str(), outputs),
    ^~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

match *some_reference在可能的情况下最好这样做,但是在这种情况下您不能这样做。因此,我们需要更新模式以匹配对Op— 的引用&Op。看看接下来会发生什么错误...

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

是我们以前的朋友。这次,我们将遵循编译器的建议,并将其更改为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));
}
Run Code Online (Sandbox Code Playgroud)
  1. 不需要use std::prelude::*;-编译器自动插入。

  2. as_str在稳定的Rust中不存在。对String(&String)的引用可以使用deref强制来充当字符串切片(&str)。

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