当前位置: 首页 > article >正文

【Rust自学】8.6. HashMap Pt.2:更新HashMap

8.6.0. 本章内容

第八章主要讲的是Rust中常见的集合。Rust中提供了很多集合类型的数据结构,这些集合可以包含很多值。但是第八章所讲的集合与数组和元组有所不同。

第八章中的集合是存储在堆内存上而非栈内存上的,这也意味着这些集合的数据大小无需在编译时就确定,在运行时它们可以动态地变大或变小。

本章主要会讲三种集合:Vector、String和HashMap(本文)

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

8.6.1. 更新HashMap

HashMap的大小可变指的是其中的键值对数量可变,但是在每个时刻一个键只能对应一个值,当想要更新HashMap中的数据的时候,可能有这么几种情况:

  • 想要更新的键在HashMap中已经存在一个对应的值:

    • 用新的值代替现有的值
    • 保留现有的值,忽略新的值
    • 合并现有的值和新的值,也就是说对现有的值进行修改
  • 键不存在:添加一对键和值

1. 替换(覆盖)现有的值

如果向HashMap插入一对键值对,但键已经存在,程序就会把新值赋给这个键,原来的就被覆盖了。如下例:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("dev1ce"), 0);  
    scores.insert(String::from("dev1ce"), 60);  
    println!("{:?}", scores)  
}

这里为通一个键赋了两次值,第一次是0,第二次是60,那么第一次的就会被第二次覆盖掉,也就是说,最终"dev1ce"对应的值是60。

输出:

{"dev1ce": 60}

2. 只在键不存在任何值的情况下才插入值

这个情况是最常见的,对于这种情况,首先需要检查原HashMap中是否已经存在这个键,如果不存在再插入新值。

Rust提供了entry这个方法来实现检查原HashMap中是否已经存在这个键的功能。它的参数为键,它的返回值是一个枚举Entry,代表值是否存在。看个例子:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("dev1ce"), 0);  
    let e = scores.entry(String::from("dev1ce"));  
    println!("{:?}", e);  
}

这是键已经存在的情况,来看一下输出:

Entry(OccupiedEntry { key: "dev1ce", value: 0, .. })

也就是说,如果键已经存在,那么entry这个方法会返回Entry枚举下的OccupiedEntry这个变体并且关联已经存在的键值对。

那来试一下键不存在的情况。代码如下:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("dev1ce"), 0);  
    let e = scores.entry(String::from("Zywoo"));  
    println!("{:?}", e);  
}

输出:

Entry(VacantEntry("Zywoo"))

如果键不存在,那么它会返回Entry枚举下的VacantEntry变体,并且关联这个新的键。

现在有办法检查原HashMap中是否已经存在这个键,那么如何根据是否存在实现插入或不插入值呢?

Rust提供了or_insert方法,其参数是想要添加的值,它可以接收Entry枚举类型,根据这个类型的两个变体来实现是否插入的功能。如果它接收到了OccupiedEntry(已经存在的情况)这个变体,它就会不插入值;反之,如果接收到了VacantEntry(不存在的情况)变体,它就不会执行插入操作。最重要的一点是,它是有返回值的,它的返回值是这个键对应值的可变引用(存在就返回HashMap中原有的键所对应的值的可变引用,不存在就先添加键值对然后返回值的可变引用),根据这个特性可以实现一些简单的计数器(后文会讲)。

看下例子:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("dev1ce"), 0);  
      
    scores.entry(String::from("Zywoo")).or_insert(100);  
    scores.entry(String::from("dev1ce")).or_insert(60);
    println!("{:?}", scores);  
}
  • 第一个entry语句查找了"Zywoo",发现没有,就返回VacantEntryor_insert接收到了,就根据VacantEntry所关联的键和传入的参数100创建了(“Zywoo”, 100)这个键值对。
  • 第二个entry语句查找了"dev1ce",发现有了,就返回OccupiedEntryor_insert接收到了,就停止插入新值,所以会保持(“dev1ce”, 0)不变。

输出:

{"Zywoo": 100, "dev1ce": 0}

如果这么讲还有些复杂,那么你可以把scores.entry(String::from("Zywoo")).or_insert(100);看作两行代码:

let e = `scores.entry(String::from("Zywoo"));
e.or_insert(100);

3.基于现有的值来更新

先看例子:

use std::collections::HashMap;  
  
fn main() {  
    let text = "That's one small step for [a] man, one giant leap for mankind.";  
  
    let mut map = HashMap::new();  
  
    for word in text.split_whitespace() {  
        let count = map.entry(word).or_insert(0);  
        *count += 1;  
    }  
    println!("{:#?}", map);  
}
  • 这个例子首先声明了一个字符串字面值,一段话,赋给了text
  • 然后创建了map这个HashMap
  • 接着使用了for循环,text.split_whitespace()就是把text分割为了一组字符串的遍历器,用for来遍历。
  • 遍历的时候,就判断单词在这个map里出现没,出现了就不插入新值了,没出现就插入0作为新的键值对。最重要的是理解count,由于or_insert方法的返回值是这个键对应值的可变引用,所以没出现一次就把值的可变引用先解引用,在自加1就相当于完成了一次统计。

8.6.2. Hash函数

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


http://www.kler.cn/a/461528.html

相关文章:

  • TT100K数据集, YOLO格式, COCO格式
  • 【前端】Node.js使用教程
  • HTML 字符编码
  • 【Python科研数据爬虫】基于国家标准查询平台和能源标准化信息平台的海上风电相关行业标准查询信息爬取及处理
  • Linux下部署Redis集群 - 一主二从三哨兵模式
  • Ps:创建数据驱动的图像
  • 智能运维分析决策系统:构建高效运维的新篇章
  • 自动化与人工结合:如何平衡效率与风险?
  • 监控 Docker 注册表
  • 基于 Slf4j 和 AOP 的自动化方法执行时间日志记录方案
  • python-Flask:SQLite数据库路径不正确但是成功访问到了数据库,并对表进行了操作
  • QT----------常用界面组件的使用
  • 2024 AI产品经理在大模型的探索与实践(附学习资料下载)
  • 低空经济迅猛发展,无人机服务拔得头筹
  • 2021-04-14 输入一个数,判断奇偶性,若是奇数乘以2,若是偶数除2,得到结果若是三位数则反序,否则输出计算结果
  • Java 溯本求源之基础(三十三)——接口
  • 使用logrotate工具来管理和轮转日志文件
  • 007-构建工具大进步:Amper Amper Amper!
  • 论文研读:Tune-a-video — 微调学习单个视频内的物体动作(Arxiv: 2023-03-17)
  • 智能边缘计算×软硬件一体化:开启全场景效能革命新征程(高校开发者作品)
  • 【MySQL初级】第5-11章
  • 职场中倾听比表达更显智慧
  • 【传感器技术】第7章 温度传感器,热电偶,热电阻,热敏电阻,集成温度传感器
  • Prometheus + Grafana 监控,验证 Hystrix 超时熔断
  • 期末速成C++【模板和STL和算法】
  • sqlserver设置定时任务计划(SSMS)