So I\'m a bit stuck, trying to merge two HashMaps.
It\'s easy to do it inline:
fn inline() {
let mut first_context = HashMap::new();
first_co
A more up to date answer from this tweet:
use std::collections::HashMap;
// Mutating one map
fn merge1(map1: &mut HashMap<(), ()>, map2: HashMap<(), ()>) {
map1.extend(map2);
}
// Without mutation
fn merge2(map1: HashMap<(), ()>, map2: HashMap<(), ()>) -> HashMap<(), ()> {
map1.into_iter().chain(map2).collect()
}
// If you only have a reference to the map to be merged in
fn merge_from_ref(map: &mut HashMap<(), ()>, map_ref: &HashMap<(), ()>) {
map.extend(map_ref.into_iter().map(|(k, v)| (k.clone(), v.clone())));
}
Rust Playground Link
This version does work:
use std::collections::HashMap;
use std::hash::Hash;
fn main() {
fn merge<K: Hash + Eq + Copy, V: Copy>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V> {
let mut new_context = HashMap::new();
for (key, value) in first_context.iter() {
new_context.insert(*key, *value);
}
for (key, value) in second_context.iter() {
new_context.insert(*key, *value);
}
new_context
}
let mut first_context = HashMap::new();
first_context.insert("Hello", "World");
let mut second_context = HashMap::new();
second_context.insert("Hey", "There");
println!("Generic:\t{}", merge(&first_context, &second_context));
println!("Generic:\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
The difference is in the signature of merge()
. Here is yours:
fn merge<'a, K: Hash + Eq, V>(first_context: &HashMap<&'a K, &'a V>, second_context: &HashMap<&'a K, &'a V>) -> HashMap<&'a K, &'a V>
Here is mine:
fn merge<K: Hash + Eq + Copy, V: Copy>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V>
For some reason you are trying to abstract HashMap<&str, &str>
to HashMap<&K, &V>
, but this is not really correct: while &str
is a borrowed pointer, it is special - it points to dynamically sized type str
. Size of str
is not known to the compiler, so you can use it only through a pointer. Consequently, neither Hash
nor Eq
are implemented for str
, they are implemented for &str
instead. Hence I've changed HashMap<&'a K, &'a V>
to HashMap<K, V>
.
The second problem is that in general you can't write your function if it takes only references to maps. Your non-generic merge function works only because &str
is a reference and references are implicitly copyable. In general case, however, both keys and values can be non-copyable, and merging them into the single map will require moving these maps into the function. Adding Copy
bound allows that.
You can also add Clone
bound instead of Copy
and use explicit clone()
call:
fn merge<K: Hash + Eq + Clone, V: Clone>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V> {
// ...
for (key, value) in first_context.iter() {
new_context.insert(key.clone(), value.clone());
}
// ...
}
The most general way, however, is moving maps into the function:
fn merge<K: Hash + Eq, V>(first_context: HashMap<K, V>, second_context: HashMap<K, V>) -> HashMap<K, V> {
// ...
for (key, value) in first_context.into_iter() {
new_context.insert(key, value);
}
// ...
}
Note into_iter()
method which consumes the map, but returns an iterator of tuples with actual values instead of references.