Rust 学习笔记(17)-HashMap

参考章节《Rust 程序设计语言》第8.3章 使用 Hash Map 储存键值对

HashMap 是一种键值对类型的容器,HashMap<K, V> 储存了一个键类型 K 对应一个值类型 V 的映射。

  • 创建HashMap
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
use std::collections::HashMap;

fn main() {
    // 可以使用 new 创建一个空的 HashMap,并使用 insert 增加元素。
    let mut map1 = HashMap::new();

    // HashMap 是同质的:所有的键必须是相同类型,值也必须都是相同类型。
    // HashMap 如果不显示指定K和V的类型,那么其K和V将会是第一次插入的数据的类型
    // 这里这个 HashMap 的键类型是 String 而值类型是 i32。
    map1.insert(String::from("aaa"), 10);
    map1.insert(String::from("bbb"), 50);

    // 另一个构建 HashMap 的方法是使用一个元组的 vector 的 collect 方法,这在某些特殊情况下会用到
    let vec = vec![String::from("aaa"), String::from("bbb")];
    let val = vec![10, 50];
    let map2: HashMap<_, _> = vec.iter().zip(val.iter()).collect();
}
  • 从HashMap中获取值
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
use std::collections::HashMap;

fn main() {
    let mut map1 = HashMap::new();
    map1.insert(String::from("aaa"), 10);
    map1.insert(String::from("bbb"), 50);

    let value_option = map1.get(&String::from("aaa")); // 注意这里返回的是一个 Option
    let value = match value_option {
        None => 0,
        Some(i) => *i,
    };
    println!("{}", value);

    // HashMap的遍历
    for (key, value) in &map1 {
        println!("{}: {}", key, value);
    }
}
  • 更新值
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use std::collections::HashMap;

fn main() {
    let mut map1 = HashMap::new();
    // 更新哈希 map
    // 尽管键值对的数量是可以增长的,不过任何时候,每个键只能关联一个值。
    // 当我们想要改变哈希 map 中的数据时,必须决定如何处理一个键已经有值了的情况。
    // 1.可以选择完全无视旧值并用新值代替旧值(覆盖)。
    // 2.可以选择保留旧值而忽略新值,并只在键没有对应值时增加新值。
    // 3.或者可以结合新旧两值。
    // 让我们看看这分别该如何处理!

    // 覆盖一个值
    // 如果我们插入了一个键值对,接着用相同的键插入一个不同的值,与这个键相关联的旧值将被替换。
    map1.insert(String::from("aaa"), 10);
    map1.insert(String::from("aaa"), 50);
    println!("{:?}", map1);

    // 只在键没有对应值时插入
    // 我们经常会检查某个特定的键是否有值,如果没有就插入一个值。
    // 为此 HashMap 有一个特有的 API,叫做 entry,它获取我们想要检查的键作为参数。
    // entry 函数的返回值是一个枚举,Entry,它代表了可能存在也可能不存在的值。
    // 比如说我们想要检查名为 aaa 的键是否关联了一个值。如果没有,就插入值 50
    let mut map2 = HashMap::new();
    map2.insert(String::from("aaa"), 10);
    map2.entry(String::from("aaa")).or_insert(50); // 因为 aaa 已经有值,因此不会再插入值了
    map2.entry(String::from("bbb")).or_insert(50);
    println!("{:?}", map2);
    // Entry 的 or_insert 方法在键对应的值存在时就返回这个值的可变引用。
    // 如果不存在则将参数作为新值插入并返回新值的可变引用。

    // 根据旧值更新一个值
    // 一个常见的哈希 map 的应用场景是找到一个键对应的值并根据旧的值更新它。
    // 例如,计数一些文本中每一个单词分别出现了多少次。
    // 我们使用哈希 map 以单词作为键并递增其值来记录我们遇到过几次这个单词。
    // 如果是第一次看到某个单词,就插入值 0。
    let text = "hello world wonderful world";
    let mut map3 = HashMap::new();
    for word in text.split_whitespace() {
        let count = map3.entry(word).or_insert(0);
        *count += 1;
    }
    println!("{:?}", map3);
    // 这个例子的最重要的部分就是entry会返回这个键的值的一个可变引用(&mut V)。
}
updatedupdated2024-10-012024-10-01