我希望我的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,
}
}
}
答案 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。