繁体   English   中英

如何在 Rust 中创建具有默认值的 HashMap?

[英]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


ArtemGr 提出了一个有趣的观点

在 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);

.or_insert() 和 .or_insert_with()

添加到.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM