Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle the value I get from a HashMap

Tags:

rust

I want my getv() function return the value from a HashMap. I get errors no matter how I modify my code:

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,
        }
    }
}
like image 249
mochi Avatar asked Dec 14 '22 19:12

mochi


1 Answers

HashMap::get returns an Option<&Type>, not an Option<Type>, which is why just returning the matched value fails to compile.

get provides a reference because in Rust you cannot simply return the actual value that is in the hash table - you need to either clone it (make a copy, potentially expensive), remove it from the container and transfer it to the caller, or return a reference to the value inside. HashMap::get chooses the last option because it is cheap while providing the greatest flexibility to the caller, which can choose to either inspect the value or clone it.

For your enum that consists of a single machine word, copying the value would be the optimal approach. (For more complex enums, a better approach is to return a reference as shown in Simon's answer.) Copying requires:

  • making Type copyable, by marking it with the Copy trait using the #[derive(Copy, Clone)] directive at the type definition.

  • returning the copy from getv by dereferencing the matched value using *matched_value, or by using & in the pattern.

Finally, your getv method consumes the object, which means that you can call it only once. This is almost certainly not what was intended - it should accept &self instead. With those changes, the resulting code looks like this:

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,
        }
    }
}

If the type needs to contain non-Copy data, then you can make it only Clone instead, and return v.clone().

like image 93
user4815162342 Avatar answered Dec 19 '22 12:12

user4815162342