【问题标题】:Pattern matching over borrowed HashMap containing enums对包含枚举的借用 HashMap 进行模式匹配
【发布时间】:2015-12-14 21:27:18
【问题描述】:

我正在尝试学习 Rust,所以如果我离题了,请耐心等待 :-)

我有一个程序可以将枚举插入HashMap,并使用Strings 作为键。我正在尝试匹配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));
}

【问题讨论】:

    标签: enums rust


    【解决方案1】:

    查看编译器错误信息是什么:

    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 的类型将是双重引用 (&amp;&amp;Op)。相反,我们只需删除&amp; 并拥有Some(op)

    这是一个常犯的错误,因为要做到这一点,您必须熟悉 模式匹配引用,以及 Rust 严格的借用检查器。当你有Some(&amp;op) 时,就是说

    匹配一个Option,它是Some的变体。 Some 必须包含对值的引用。被引用的东西应该从它所在的位置移出并放入op

    模式匹配时,refmut这两个关键字可以发挥作用。这些是 not 模式匹配的,而是控制值如何绑定到变量名。它们是&amp;mut 的类似物。

    这导致我们出现下一个错误:

    error: mismatched types:
     expected `&Op`,
        found `Op`
    
        Op::Not(input) => return eval_output(input.as_str(), outputs),
        ^~~~~~~~~~~~~~
    

    如果可能,最好使用match *some_reference,但在这种情况下你不能。所以我们需要更新模式以匹配对Op 的引用——&amp;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 (&amp;String) 的引用可以使用deref coercions 来充当字符串切片(&amp;str)。

    3. 我使用了into 而不是String::from,因为它有点短。没有更好的理由。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 2014-04-10
      • 2015-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多