'Get real value or None from a HashMap
I have a struct that I would like to fill based on a potentially incomplete hash map:
#[derive(Debug)]
struct Sue {
children: Option<u8>,
cats: Option<u8>,
samoyeds: Option<u8>,
pomeranians: Option<u8>,
akitas: Option<u8>,
vizslas: Option<u8>,
goldfish: Option<u8>,
trees: Option<u8>,
cars: Option<u8>,
perfumes: Option<u8>,
}
impl Sue {
fn from_line(line: &str) -> Sue {
let data: Vec<&str> = line.split(" ").collect();
let items: HashMap<String, u8> = data[2..data.len()]
.chunks(2)
.map(|item| {
(
String::from(item[0].trim_end_matches(":")),
String::from(item[1].trim_end_matches(",")).parse().unwrap(),
)
})
.collect();
println!("{:?}\n", items);
Sue {
// children: match items.get("children"){
// Some(val) => Some(*val),
// None => None,
// },
children: *items.get("children"),
// cats: Some(0),
// samoyeds: Some(0),
// pomeranians: Some(0),
// akitas: Some(0),
// vizslas: Some(0),
// goldfish: Some(0),
// trees: Some(0),
// cars: Some(0),
// perfumes: Some(0),
}
}
}
In the snippet above, the items hash map may or may not contain a key for each field of the Sue struct. My idea was to build a hash map with the input, and then for each field of the struct, try to access the corresponding key of the hashmap. If the key is in the hashmap, return the dereferenced value. If the key isn't in the hashmap, return None.
I know I can do that with a match (there is a couple of lines commented showing how I would do this), but I was wondering if there is a more efficient way to do this (it's a lot of boilerplate; one match for each field).
If I run the code above, I'll get:
error[E0614]: type `Option<&u8>` cannot be dereferenced
Any idea? I do want to keep None if the key isn't found. Also for reference, this snippet is for advent of code 2015 day 16.
Solution 1:[1]
For u8, either of the methods John Kugelman mentioned work great. However, there are some types that are neither Copy nor cheaply cloneable (maybe they don't implement Clone at all, or they do but it is costly).
A third option is to remove the item from the map:
struct ExpensiveClone(u8);
impl Clone for ExpensiveClone {
fn clone(&self) -> Self {
std::thread::sleep(Duration::from_secs(1));
Self(self.0)
}
}
In this case, cloning would likely be prohibitively expensive. Instead, if you have owned or mutable access to the map, you can remove it, transferring ownership of the value from the map to your function, without needing to clone the data:
let mut map = HashMap::new();
map.insert(1, ExpensiveClone(1));
let expensive_clone = map.remove(&1).unwrap();
assert_eq!(expensive_clone.0, 1);
It goes without saying that this only works if you can modify the map though
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | cameron1024 |
