所以我有点卡住了,试图合并两个HashMaps。
内联很容易:
fn inline() {
let mut first_context = HashMap::new();
first_context.insert("Hello", "World");
let mut second_context = HashMap::new();
second_context.insert("Hey", "There");
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);
}
println!("Inline:\t\t{}", new_context);
println!("Inline:\t\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
制作一个功能很容易:
fn abstracted() {
fn merge<'a>(first_context: &HashMap<&'a str, &'a str>, second_context: &HashMap<&'a str, &'a str>) -> HashMap<&'a str, &'a str> {
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!("Abstracted:\t{}", merge(&first_context, &second_context));
println!("Abstracted:\t{}\t{} [Initial Maps Still Usable]", first_context, second_context);
}
但是,我似乎无法使用通用版本:
fn generic() {
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> {
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 above code on play.rust-lang.org
编译:
error: the trait `core::kinds::Sized` is not implemented for the type `str`
我得知编译器对通用值的大小感到困惑,但我不确定为什么“str”没有严格的内存大小?我知道它是一个字符串切片,而不是一个类型,但仍然这应该工作,不是吗?这是一个错误吗?
我认为这将是一个相对微不足道的功能。如果有人有一个好的解决方案,我很乐意学习。实际上,理想情况下,我希望看到一个带有trait Mergeable
的解决方案并为HashMap&lt;&amp; K,&amp; V&gt;写一个装饰器,这样我就可以调用let new_context = first_context.merge(&second_context);
但这可能是一个不同的问题
答案 0 :(得分:10)
来自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())));
}
答案 1 :(得分:5)
此版本确实有效:
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);
}
区别在于merge()
的签名。这是你的:
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>
这是我的:
fn merge<K: Hash + Eq + Copy, V: Copy>(first_context: &HashMap<K, V>, second_context: &HashMap<K, V>) -> HashMap<K, V>
出于某种原因,你试图将HashMap<&str, &str>
抽象为HashMap<&K, &V>
,但这不是真的正确:虽然&str
是借来的指针,但它是special - 它指向动态大小的类型str
。编译器不知道str
的大小,因此您只能通过指针使用它。因此,Hash
未实现Eq
和str
,而是为&str
实施了HashMap<&'a K, &'a V>
。因此,我已将HashMap<K, V>
更改为&str
。
第二个问题是,如果仅引用地图,则通常无法编写函数。您的非泛型合并函数仅适用于Copy
是引用,并且引用可隐式复制。但是,在一般情况下,键和值都可以是不可复制的,并且将它们合并到单个映射中将需要将这些映射移动到函数中。添加Clone
bound允许这样做。
您还可以添加Copy
绑定而不是clone()
并使用显式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());
}
// ...
}
调用:
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);
}
// ...
}
然而,最通用的方法是将地图移动到函数中:
into_iter()
注意使用地图的{{1}}方法,但返回带有实际值而不是引用的元组迭代器。