HashMap

  • 键值对的形式存储数据,一个键(Key)对应一个值(Value)
  • Hash 函数:决定如何在内存中存放 K 和 V
  • 适用场景:通过 K (任何类型) 来寻找数据,而不是通过索引

    创建 HashMap

  • 创建空 HashMap:new() 函数

  • 添加数据:insert() 方法 ```rust use std::collections::HashMap;

fn main() { // 显示指明类型 或 添加数据 let mut scores: HashMap = HashMap::new(); }

  1. ```rust
  2. use std::collections::HashMap;
  3. fn main() {
  4. let mut scores = HashMap::new();
  5. scores.insert(String::from("Blue"), 10);
  6. }

HashMap 相关说明

  • HashMap 使用的较少,不在 Prelude 中 (预导入模块)
  • 标准库对其支持较少,没有内置的宏来创建 HashMap
  • 数据存储在 heap 上
  • 同构的。一个 HashMap 中:

    • 所有的 K 必须是同一种类型
    • 所有的 V 必须是同一种类型

      另一种创建 HashMap 的方式:collect 方法

  • 在元素类型为 Tuple 的 Vector 上使用 collect 方法,可以组件一个 HashMap

    • 要求 Tuple 有两个值L一个作为 K,一个作为 V
    • collect 方法可以把数据整合成很多种集合类型,包括 HashMap
      • 返回值需要显式指明类型 ```rust use std::collections::HashMap;

fn main() { let teams = vec![String::from(“Blue”), String::from(“Yellow”)]; // String 类型作为球队名称 let initial_scores = vec![10, 50]; // i32 类型作为球队分数

  1. let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
  2. println!("{:?}", scores);

}

  1. > iter() 方法返回遍历器,使用 zip() 方法创建元组的数组,再使用 collect() 创建 HashMap
  2. > collect() 可以返回很多种不同的集合数据结构,所以需要显式的指明。
  3. > K V 使用两个下划线,因为 Rust 会根据 Vetror 中的数据类型,能推导出 HashMap K V 类型
  4. <a name="SlR77"></a>
  5. ### HashMap 和所有权
  6. - 对于实现了 Copy trait 的类型(例如:i32),值会被复制到 HashMap 中。
  7. - 对于拥有所有权的值(例如 String),值会被移动,所有权会转移给 HashMap
  8. ```rust
  9. use std::collections::HashMap;
  10. fn main() {
  11. let field_name = String::from("Favorite color");
  12. let field_value = String::from("Blue");
  13. let mut map = HashMap::new();
  14. map.insert(field_name, field_value);
  15. println!("{:?}", map);
  16. println!("{}: {}", field_name, field_value); // error: borrow of moved value
  17. }
  • 如果将值的引用插入到 HashMap,值本身就不会移动 ```rust use std::collections::HashMap;

fn main() { let field_name = String::from(“Favorite color”); let field_value = String::from(“Blue”);

  1. let mut map = HashMap::new();
  2. map.insert(&field_name, &field_value); // 使用值的引用
  3. println!("{:?}", map);
  4. println!("{}: {}", field_name, field_value);

}

  1. - HashMap 有效的期间,被引用的值必须保持有效
  2. <a name="mwn8Q"></a>
  3. ### 访问 HashMap 中的值
  4. - get 方法
  5. - 参数:K
  6. - 返回:Option<&V> (返回空的枚举)
  7. ```rust
  8. use std::collections::HashMap;
  9. fn main() {
  10. let mut scores = HashMap::new();
  11. scores.insert(String::from("Blue"), 10);
  12. scores.insert(String::from("Yellow"), 50);
  13. let team_name = String::from("Blue");
  14. let score = scores.get(&team_name);
  15. match score {
  16. Some(s) => println!("{}", s),
  17. None => println!("team not exist"),
  18. };
  19. }

遍历 HashMap

  • for 循环 ```rust use std::collections::HashMap;

fn main() { let mut scores = HashMap::new(); scores.insert(String::from(“Blue”), 10); scores.insert(String::from(“Yellow”), 50); for (k, v) in &scores { // (k, v) 模式匹配相当于元组 println!(“{}: {}”, k, v); } }

  1. <a name="aHyn2"></a>
  2. ### 更新 HashMap<K, V>
  3. - HashMap 大小可变
  4. - 每个 K 同时只能对应一个 V
  5. - 更新 HashMap 中的数据:
  6. - K 已经存在,对应一个 V
  7. - 替换现有的 V
  8. - 保留现有的 V,忽略新的 V
  9. - 合并现有的 V 和新的 V
  10. - K 不存在
  11. - 添加一对新的 K,V
  12. <a name="QS5sR"></a>
  13. #### 替换现有的 V
  14. - 如果向 HashMap 插入一对 K,V,然后再插入同样的 K,但是不同的 V,那么原来的 V 会被替换掉。
  15. ```rust
  16. use std::collections::HashMap;
  17. fn main() {
  18. let mut scores = HashMap::new();
  19. scores.insert(String::from("Blue"), 10);
  20. scores.insert(String::from("Blue"), 25);
  21. println!("{:?}", scores);
  22. }

只在 K 不对应任何值的情况下,才插入 V

  • entry 方法:检查指定的 K 是否对应一个 V
    • 参数:K
    • 返回 enum Entry:代表值是否存在 ```rust use std::collections::HashMap;

fn main() { let mut scores = HashMap::new(); scores.insert(String::from(“Blue”), 10);

  1. scores.entry(String::from("Yellow")).or_insert(50);
  2. scores.entry(String::from("Blue")).or_insert(50);
  3. println!("{:?}", scores); // {"Blue": 10, "Yellow": 50}

}

  1. - entry or_insert() 方法:
  2. - 返回:
  3. - 如果 K 存在,返回对应的 V 的一个可变引用
  4. - 如果 K 不存在,将方法参数作为 K 的新值插进去,返回到这个值的可变引用
  5. <a name="tEnrc"></a>
  6. #### 基于现有 V 来更新 V
  7. ```rust
  8. use std::collections::HashMap;
  9. fn main() {
  10. let text = "hello world wonderful world";
  11. let mut map = HashMap::new();
  12. for word in text.split_whitespace() {
  13. let count = map.entry(word).or_insert(0);
  14. *count += 1;
  15. }
  16. println!("{:#?}", map); // {"hello": 1, "world": 2, "wonderful": 1}
  17. }

Hash 函数

  • 默认情况下,HashMap 使用加密功能强大的 Hash 函数,可以抵抗拒绝服务 (DoS) 攻击。
    • 不是可用的最快的 Hash 算法
    • 但具有更好的安全性
  • 可以指定不同的 hasher 来切换到另一个函数
    • hasher 是实现 BuildHasher trait 的类型