[英]How do I create a Rust HashMap where the value can be one of multiple types?
[英]How does one create a HashMap with a default value in Rust?
作为 Rust 的新手,我想知道如何使用键的默认值创建HashMap
? 例如,对于HashMap
中插入的任何键,都具有默认值0
。
在 Rust 中,我知道这会创建一个空的 HashMap:
let mut mymap: HashMap<char, usize> = HashMap::new();
我希望为一组键维护一个计数器,其中一种方法似乎是:
for ch in "AABCCDDD".chars() {
mymap.insert(ch, 0)
}
有没有办法在 Rust 中以更好的方式做到这一点,也许相当于 Ruby 提供的东西:
mymap = Hash.new(0)
mymap["b"] = 1
mymap["a"] # 0
回答你遇到的问题...
我希望为一组键维护一个计数器。
然后你想看看如何有效地查找并插入 HashMap? . 提示: *map.entry(key).or_insert(0) += 1
回答你问的问题...
如何在 Rust 中创建具有默认值的 HashMap?
不, HashMap
没有存储默认值的地方。 这样做会导致该数据结构的每个用户都分配空间来存储它,这将是一种浪费。 您还必须处理没有适当默认值或无法轻松创建默认值的情况。
相反,您可以使用HashMap::get
查找值,并在缺少时使用Option::unwrap_or
提供默认值:
use std::collections::HashMap;
fn main() {
let mut map: HashMap<char, usize> = HashMap::new();
map.insert('a', 42);
let a = map.get(&'a').cloned().unwrap_or(0);
let b = map.get(&'b').cloned().unwrap_or(0);
println!("{}, {}", a, b); // 42, 0
}
如果unwrap_or
不适用于您的情况,有几个类似的功能可能:
当然,欢迎您将其包装在函数或数据结构中以提供更好的 API 。
在 C++ 中,有一个映射的概念,即在访问键时插入默认值。 不过,这似乎总是有点漏:如果类型没有默认值怎么办? Rust 对映射类型的要求较低,并且对键的存在(或不存在)更为明确。
Rust 对此增加了额外的皱纹。 实际上插入一个值需要简单地获取一个值也可以更改HashMap
。 这将使对HashMap
中值的任何现有引用无效,因为可能需要重新分配。 因此,您将不再能够同时获得对两个值的引用! 那将是非常严格的。
使用entry
从 HashMap 中获取一个元素,然后修改它呢?
从文档:
fn entry(&mut self, key: K) -> Entry<K, V>
获取地图中给定键的对应条目以进行就地操作。
use std::collections::HashMap;
let mut letters = HashMap::new();
for ch in "a short treatise on fungi".chars() {
let counter = letters.entry(ch).or_insert(0);
*counter += 1;
}
assert_eq!(letters[&'s'], 2);
assert_eq!(letters[&'t'], 3);
assert_eq!(letters[&'u'], 1);
assert_eq!(letters.get(&'y'), None);
添加到.entry().or_insert()
的现有示例中,我想提一下,如果传递给.or_insert()
的默认值是动态生成的,最好使用.or_insert_with()
。
使用.or_insert_with()
如下,如果键已经存在,则不会生成默认值。 它仅在必要时创建。
for v in 0..s.len() {
components.entry(unions.get_root(v))
.or_insert_with(|| vec![]) // vec only created if needed.
.push(v);
}
在下面的片段中,每次调用都会生成传递给.or_insert()
的默认向量。 如果密钥存在,则会创建一个向量,然后将其丢弃,这可能是一种浪费。
components.entry(unions.get_root(v))
.or_insert(vec![]) // vec always created.
.push(v);
因此,对于没有太多创建开销的固定值,请使用.or_insert()
,对于具有可观创建开销的值,请使用.or_insert_with()
。
使用初始值启动映射的一种方法是从元组向量构造映射。 例如,考虑下面的代码:
let map = vec![("field1".to_string(), value1), ("field2".to_string(), value2)].into_iter().collect::<HashMap<_, _>>();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.