如何处理从HashMap获得的值

时间:2017-11-14 06:03:59

标签: rust

我希望我的getv()函数返回HashMap的值。无论我如何修改代码,我都会收到错误:

enum Type {
    TyInt,
    TyBool,
}

struct TypeEnv {
    Env: HashMap<char, Type>,
}
impl TypeEnv {
    fn set(&mut self, name: char, ty: Type) {
        self.Env.insert(name, ty);
    }

    fn getv(self, name: char) -> Type {
        match self.Env.get(&name) {
            Some(Type) => Type, // <------- Always error here
            None => Type::TyInt,
        }
    }
}

2 个答案:

答案 0 :(得分:5)

HashMap::get返回Option<&Type>,而不是Option<Type>,这就是为什么只返回匹配的值无法编译。

get提供了一个引用,因为在Rust中你不能简单地返回哈希表中的实际值 - 你需要克隆它(制作副本,可能很昂贵), 从容器中删除并将其传输给调用者,或者将引用返回到内部值。 HashMap::get选择最后一个选项,因为它是便宜的,同时为调用者​​提供了最大的灵活性,可以选择检查值或克隆它。

对于包含单个机器字的枚举,复制值将是最佳方法。 (对于更复杂的枚举,更好的方法是返回Simon's answer中显示的引用。)复制需要:

  • 通过在类型定义中使用Type指令使用Copy特征标记#[derive(Copy, Clone)]来复制getv

  • 通过使用*matched_value取消引用匹配的值或在模式中使用&来从getv返回副本。

最后,您的&self方法会使用该对象,这意味着您只能调用一次。这几乎肯定不是预期的 - 它应该接受use std::collections::HashMap; #[derive(Copy, Clone)] enum Type { TyInt, TyBool, } struct TypeEnv { env: HashMap<char, Type>, } impl TypeEnv { fn set(&mut self, name: char, ty: Type) { self.env.insert(name, ty); } fn getv(&self, name: char) -> Type { match self.env.get(&name) { Some(&v) => v, None => Type::TyInt, } } } 。通过这些更改,生成的代码如下所示:

Copy

如果类型需要包含非Clone数据,那么您只能将其设为v.clone(),并返回FIRST_VALUE

答案 1 :(得分:3)

如果您对参考文献感到满意,则

当写这样的东西时会弹出这样的东西,通常最好重新评估你是如何调用代码的。它会变得更简单吗?

你可以让调用者期望Copy,或者只是强迫某些东西 ...也许是这样的:

Clone

这简化了您的代码,并且非常清楚您所追求的内容。 Here it is in action

Option<&V>

此外,您现有的fn getv(&self, name: char) -> &Type { self.env.get(&name).unwrap_or(&Type::TyInt) } 实施权归use std::collections::HashMap; #[derive(Debug)] enum Type { TyInt, TyBool, } struct TypeEnv { env: HashMap<char, Type>, } impl TypeEnv { fn set(&mut self, name: char, ty: Type) { self.env.insert(name, ty); } fn getv(&self, name: char) -> &Type { self.env.get(&name).unwrap_or(&Type::TyInt) } } fn main() { let mut te = TypeEnv { env: HashMap::new(), }; { let arg = te.getv('c'); println!("{:?}", arg); // "TyInt" - because nothing was found } te.set('c', Type::TyBool); let arg = te.getv('c'); // "TyBool" - because we stored it in the line above. println!("{:?}", arg); } 所有......请注意我添加了引用getv的方式。如果你没有这个,这种类型(据我所知)变为basically useless