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

【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.lryc.cn/news/514193.html

相关文章:

  • Python异常处理详解:概念、语法与实践
  • Kotlin在医疗大健康域的应用实例探究与编程剖析(上)
  • QT----------QT Data Visualzation
  • 什么是Sight Words(信号词)
  • SpringBoot日志快速集成详解-生产实战
  • 路由技术在网络中的作用及特点
  • 【Python系列】Flask 与 FastAPI:两个 Python Web 框架的对比分析
  • 云手机:虚拟技术的革命性应用与实体手机的优劣对比
  • 3. C语言 数据类型
  • npm install 安装选项 -d -s -g
  • pdf预览兼容问题- chrome浏览器105及一下预览不了
  • 【可实战】需求分析-测试计划↓-测试设计-测试执行-测试总结↓(包含测试计划、测试总结模板,以公司要求为准)
  • MySQL 03 章——基本的SELECT语句
  • 【项目】智能BI洞察引擎 测试报告
  • javaEE-文件操作和IO-文件
  • 2025跨年倒计时
  • 下载mysql免安装版和配置
  • 代码模板-C语言常用的errno的名字、值以及对应关系?转换字符串函数?(errno.h, strerror; errno -l; man errno)
  • 全新免押租赁系统助力商品流通高效安全
  • 5.微服务灰度发布落地实践(rocketmq增强)
  • MySql核心面试面试问题解析
  • logback之自定义pattern使用的转换器
  • 【MySQL】发展起源与核心架构组件详细介绍
  • uni-app 多平台分享实现指南
  • Spring中的IOC是什么,优缺点有哪些?
  • Qt实现使用TCP与RS485串口设备通信————附带详细实践方法
  • js将object整个实体对象作为参数传递
  • 超越局部损失函数的预测-优化方法
  • PDF预览插件
  • node.js之---CommonJS 模块