简介
- 接上回书
什么叫HashMap
- HashMap实际上就是通过键值对的形式存储的堆。
创建 HashMap
- 创建空HashMap: new() 函数
- 添加数据通过:insert() 方法
- HashMap 不在预加载中,所以需要通过
use std::collections::HashMap
进行加载后使用 - HashMap 也是必须是同构的(K必须是同一类型、V必须是同一类型。)
另外一种创建 HashMap 的方式
- 在元素类型为Tuple的Vector 上使用 collect 方法,可以组件HashMap,但必须满足:
1、Tuple 有两个值,一个作为K,一个作为V
2、collect 方法可以把数据整合成很多种集合类型,包括HashMap
3、返回值需要显示知名类型
- 举例:
use std::collections::HashMap;
fn main() {
let keys = vec!["linhai".to_string(), "changlong".to_string()] ;
let ages = vec![38, 26];
let map :HashMap<_,_> = keys.iter().zip(ages.iter()).collect();
println!("{:?}", map);
}
HashMap 的所有权
- Rust 的所有权概念十分重要,这里简单了解一下HashMap的所有权概念。
- 对于实现了 Copy trait 的类型(比如i32),值会被复制到HashMap中。
- 对于拥有所有权的值,比如(String),值会被移动,所有权会交给HashMap
- 如果将值的引用插入到HashMap 中,值本身不会移动
- 举个简单的例子:(注意看注释的内容)
use std::collections::HashMap;
fn main() {
let name = "linhai".to_string();
let age = 36;
let mut map = HashMap::new();
map.insert(name, age);
println!("{:?}", &map);
println!("age因为是值COPY所以还是可以访问的:{}", age);
// 此时name 的所有权因为交给map这个变量就无法访问了,编译会报错。`value borrowed here after move`
// println!("name的所有权转移了,所以就无法访问了{}", name);
}
HashMap 的访问
- 可通过下标的方式访问
HashMap[index]
。 - 通过
get(key)
方法进行访问,返回值是一个Option<&V>
// 还是通过修改上面的例子实现。
use std::collections::HashMap;
fn main() {
let name = "linhai".to_string();
let age = 36;
let mut map = HashMap::new();
map.insert(name, age);
println!("{:?}", &map);
// 尝试获取 "linhai" 的年龄
match map.get("linhai") {
Some(v) => {
println!("年龄是:{}", v);
},
None => {
println!("没有找到对应值。");
},
}
}
HashMap 的遍历
- 通过for 循环加上Tuple取值定义即可,举例:
use std::collections::HashMap;
fn main() {
let name = "LinHai".to_string();
let age = 36;
let mut map = HashMap::new();
map.insert(name, age);
map.insert(String::from("HouChangLong"), 26);
println!("{:?}", &map);
// 遍历 HashMap 的元素值
for (k, v) in map {
println!("{}的年龄是{}", k, v);
}
}
HashMap 的更新
- 首先如果HashMap 想要更新那么他必须被声明为 mnt 可变类型。
- 之前已经用过
HashMap.insert()
该方法用于新插入值。 -
entry(V
用于查找某个Key值是不是存在,这个东西返回) Entry
类型,如果查找失败返回Entry(VacantEntry("ErLei"))
,如果查找成功返回Entry(OccupiedEntry { key: "LinHai", value: 36 })
,举例如下:
use std::collections::HashMap;
fn main() {
let name = "LinHai".to_string();
let age = 36;
let mut map = HashMap::new();
map.insert(name, age);
map.insert(String::from("HouChangLong"), 26);
// entry 必须传原值
let result = map.entry("ErLei".to_string());
println!("{:?}", result);
let result = map.entry("LinHai".to_string());
println!("{:?}", result);
}
// 输出结果如下:
// Entry(VacantEntry("ErLei"))
// Entry(OccupiedEntry { key: "LinHai", value: 36 })
-
or_insert(V
方法用当 Entry 枚举变体为 OccupiedEntry 是完成插入操作,使用实例如下:)
use std::collections::HashMap;
fn main() {
let name = "LinHai".to_string();
let age = 36;
let mut map = HashMap::new();
map.insert(name, age);
map.insert(String::from("HouChangLong"), 26);
// entry + or_insert 完成不存在则添加的操作
map.entry("ErLei".to_string()).or_insert(28);
map.entry("HouChangLong".to_string()).or_insert(0);
// 打印之后会看到 ErLei 的数据被加进来,HouChangLong 的数据也没有被覆盖。
println!("{:?}", map);
}
- 一个更有趣的例子,查找字符串中重复出现的字母
use std::collections::HashMap;
fn main() {
// 定义一段文本字面值
let words = "May you have enough happiness to make you sweet,enough trials to make you strong,enough sorrow to keep you human,enough hope to make you happy? Always put yourself in others’shoes.If you feel that it hurts you,it probably hurts the other person, too.";
// 定义一个统计用的Map
let mut countmap:HashMap<&str,i32> = HashMap::new();
for word in words.split_whitespace() {
// 如果存在插入一个0
let count = countmap.entry(word).or_insert(0);
*count += 1;
}
println!("统计结果:{:?}", countmap);
}
-
可以看到you 出现的次数最多:
看一个比较有意思的 BTreeMap
- 参考文档:https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
- BTreeMap 使用上和 HashMap差不错,但是存储结构会不一样。
结束
- 感谢阅读。