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

【Rust自学】8.5. HashMap Pt.1:HashMap的定义、创建、合并与访问

8.5.0. 本章内容

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

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

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

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

8.5.1. 什么是HashMap

HashMap的形式是HashMap<K,V>,其中K代表键(key),V代表值(value)。HashMap以键值对的形式存储数据,一个键对应一个值。很多语言都支持这样的集合数据结构,但是不一定是这个叫法,比如说C#中相同概念的数据结构叫字典(dictionary)。

HashMap的内部实现使用了Hash函数,中文叫哈希函数,这个函数决定了如何在内存中存储键与值。

Vector中我们使用索引来访问数据,但有的时候你想要的是通过键(键可以是任何数据类型)来寻找数据,而不是通过索引(或者说你不清楚这个数据在哪个索引)。这种情况就可以使用HashMap。

需要注意的是,HashMap是同构的,也就是说在一个HashMap中,所有的键必须是同一类型,所有的值必须是同一类型。

8.5.2. 创建HashMap

  • 由于HashMap不常用,所以Rust并没有把它集成到预导入模块(Prelude),使用前需要引入HashMap,在代码开头写上:use std::collections::HashMap;
  • 创建空的HashMap使用Hash::new()函数
  • 添加数据使用insert()方法

看个例子:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores:HashMap<String, i32> = HashMap::new();  
}

在这里创建了一个名为scores的变量来存储HashMap,由于Rust是强语言类型,它必须知道你在HashMap里存储什么数据类型。又因为没有前后文可供编译器推断,所以在声明时就必须把HashMap里键和值的数据类型显式声明出来,在代码中就是scores的键被设为了String类型,值被设为了i32类型。

当然,如果你在后文给这个HashMap上添加了数据,Rust就会根据添加的数据类型自动推断键和值的数据类型。添加数据使用insert()方法。例子如下:

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

因为在第5行往scores里添加了键值对,且键String::from("dev1ce")String类型,值0是i32(Rust默认整数是i32)类型,所以编译器就会自己推断出scores是一个HashMap<String, i32>类型的HashMap,因此第四行在声明时就不需要显式声明了。

8.5.3. 将两个Vector合为一个HashMap

在元素类型为元组的Vector上使用collect方法,可以使用HashMap。换个说法,假如你有两个Vector,这两个Vector上的所有值都有一一对应关系,这个时候就可以使用collect方法,把一个Vector里的数据作为键,另一个作为值,放到HashMap里。如下例:

use std::collections::HashMap;  
  
fn main() {  
    let player = vec![String::from("dev1ce"), String::from("Zywoo")];  
    let initial_scores = vec![0, 100];  
    let scores: HashMap<_, _> = player.iter().zip(initial_scores.iter()).collect();  
}
  • player这个Vector是用来存储选手名字的,里面的元素是String类型
  • initial_scores这个Vector是用来存储每个选手对应的得分的
  • player.iter()initial_scores.iter()是两个Vector的遍历器,使用.zip()方法就可以创建一个元组的数组,player.iter().zip(initial_scores.iter())就是创建一个player中的元素在前,initial_scores中的元素在后的元组数组,想换元素位置就可以把代码中的两个迭代器呼唤位置即可。然后再使用.collect()方法来把元组转化为HashMap。
  • 最后要注意的一点是.collect()它支持转换为很多数据结构,如果声明时不显式声明其类型程序就会报错,这里就指明了类型是HashMap<_, _><>中的两个数据类型编译器可以根据代码(也就是找两个的Vector的数据类型)来推断,所以这里可以写_占位符让它自行推断。

8.5.4. HashMap和所有权

对于实现了Copy trait的数据类型(例如i32在内的绝大多数简单数据类型),值会被复制到HashMap中,原先的变量仍然可用。对于没有实现的(例如String),所有权会被交给HashMap。

如果将值的引用插入到HashMap,值本身就不会移动。在HashMap的有效期间,被引用的值必须保持有效。

8.5.5. 访问HashMap中的值

访问值可以使用get方法。get方法的参数是HashMap的键,返回值是Option<&V>这个枚举。看个例子:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("dev1ce"), 0);  
    scores.insert(String::from("Zywoo"), 100);
      
    let player_name = String::from("dev1ce");  
    let score = scores.get(&player_name);  
    match score {  
        Some(score) => println!("{}", score),  
        None => println!("Player not found"),  
    };  
}
  • 首先创建了一个空的HashMap叫做scores,然后又通过insert方法往里面添加了两个键值对(“dev1ce”, 0)和(“Zywoo”, 100),键类型是String,值类型是i32
  • 然后又声明了名为player_nameString变量,其值为"dev1ce"。
  • 接着就通过HashMap上的get方法在scoresplayer_name&表示引用)这个键所对应的值,但是get方法返回的是Option枚举,所以这里先把这个Option枚举值赋给score后面再来解包。
  • 最后使用了match表达式来处理score,如果找到了对应的值,score这个枚举类型就会是变体Some,把Some所关联的值绑定在score上,然后再打印出来。如果找不到,score这个枚举类型就会是变体None,这个时候就会打印"Player not found"。

输出:

0

8.5.6. 遍历HashMap

遍历HashMap一般使用for循环。如下例:

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("dev1ce"), 0);  
    scores.insert(String::from("Zywoo"), 100);  
    for (k, v) in &scores {  
        println!("{}: {}", k, v);  
    }  
}

这个for循环使用的是HashMap的引用,也就是&scores,因为通常遍历之后还要继续使用这个HashMap,所以使用引用就不会失去所有权,前面的(k,v)是一个模式匹配,第一个值就是键,这里赋给了k;第二个是值,这里赋给了v

输出:

Zywoo: 100
dev1ce: 0

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

相关文章:

  • Java重要面试名词整理(十七):Nacos
  • 深入浅出梯度下降与反向传播
  • 如何在没有 iCloud 的情况下将联系人从 iPhone 传输到 iPhone
  • MySQL 中的触发器:优点和缺点
  • 使用交换机构建简单局域网
  • 九垠赢+商业管理系统 Common.ashx 文件上传致RCE漏洞复现
  • 复合机器人赋能食品饮料加工行业向自动化升级改造
  • OpenCV相机标定与3D重建(39)计算校正畸变后的新相机内参矩阵函数getOptimalNewCameraMatrix()的使用
  • 数据的高级处理——pandas模块进阶——数据的查找和替换
  • Linux ipmitool工具使用笔记
  • 输入ssh-add ~/.ssh/login ,显示Enter passphrase for /c/Users/.ssh/login:
  • UniApp 原生插件开发指南
  • C# OpenCV机器视觉:车牌识别
  • 基于深度学习的语音识别系统实现:开启语音交互的新时代
  • VScode 格式化代码空格记录
  • Python软体中使用 Celery 与 RabbitMQ 实现高效异步任务队列:完整部署与实战指南
  • Webpack 优化全攻略:彻底解决 Vue 项目 npm run dev 的内存泄露问题
  • MySQL数据库——常见慢查询优化方式
  • 图像/特征相似计算
  • PostgreSQL数据库缓冲区管理模块