【Rust语言】std::collections::HashMap用法
HashMap用法文档
文章目录
- 创建
- 键的要求
- 增删改查
- 增: insert
- 删: remove/remove_entry
- 改
- 单点修改 get_mut
- 整体修改 values_mut/iter_mut
- 查
- 集增改于一身的entry
- 遍历
- 只读遍历
- into_values() 与 into_keys()
- 容量、实际长度、判空
- 导出
- 清除
- 重定容量
use std::collections::HashMap;
创建
// 最简单的写法
let mut my_map = HashMap::new();
// 写全了就是 ↓
let mut map: HashMap<&str, i32> = HashMap::new();
// 规定初始容量
let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
// 创建一个使用随机哈希器的 HashMap
use std::hash::RandomState;
let s = RandomState::new();
let mut map = HashMap::with_hasher(s);
// 使用随机哈希器 并且规定初始容量
let mut map = HashMap::with_capacity_and_hasher(10, s);
键的要求
键需要实现 Eq 和 Hash 特征,通常可以使用默认
#[derive(Partial Eq, Eq, Hash)]
如果您自己实现这些属性,则以下属性必须成立:
k1 == k2 -> hash(k1) == hash(k2)
增删改查
增: insert
将键值对插入到映射中。
如果映射不存在此键,则返回 None。
如果映射确实存在此键,则更新该值并返回旧值。
my_map.insert("Daniel", "798-1364");
删: remove/remove_entry
map.remove(&1)
map.remove_entry(&1);
返回Option,若map中有key==1的,则返回Some((1, “a”), 否则返回None
改
单点修改 get_mut
返回对与 key 对应的值的可变引用。
键可以是映射的键类型的任何借用形式,但借用形式的 Hash 和 Eq 必须与键类型的 Hash 和 Eq 匹配。
// if let 的用法:返回None,则 if语句中不执行(不会报错)
if let Some(x) = map.get_mut(&1) {
*x = "b";
}
整体修改 values_mut/iter_mut
for (_, val) in map.iter_mut() {
*val *= 2;
}
for val in map.values_mut() {
*val = *val + 10;
}
思考:为什么没有key_mut?
答:因为hash map中的key不可改
查
assert_eq!(map.contains_key(&1), true);// 返回bool类型
map.get_key_value(&1); //返回Option<(&K, &V)类型
map.get(&1)// 返回Option<&V>类型
集增改于一身的entry
letters.entry(ch).and_modify(|counter| *counter += 1).or_insert(1);
解释:
letters.entry(ch):
letters 是一个 HashMap,其中 entry 方法被调用。这个方法接受一个键(在这个例子中是 ch),并返回一个 Entry 类型的值,代表映射中与该键关联的值的入口点。
Entry API 提供了一种方式来迭代、插入或修改映射中的值,而不需要直接使用 get、insert 或 get_mut 方法。
.and_modify(|counter| *counter += 1):
and_modify 方法是一个在 Entry API 中使用的方法,它用于修改已存在的值。如果键 ch 已经存在于映射中,这个方法将被调用。
它接受一个闭包 |counter| *counter += 1,这个闭包接受一个可变引用 counter 到当前的计数值,并递增这个值。这里 *counter += 1 相当于 counter = counter + 1,但使用了解引用操作符 * 来修改值。
.or_insert(1):
or_insert 方法是 Entry API 的一部分,用于处理键不存在的情况。如果 ch 不在映射中,这个方法将被调用。
它接受一个值(在这个例子中是 1),并将这个值插入到映射中作为 ch 的值。如果 ch 已经存在,这个方法不会做任何事情。
综合来看,这行代码的作用是:
-
如果 ch 已经作为键存在于 letters 映射中,就将其对应的值增加 1。
-
如果 ch 不存在,就在映射中插入 ch 作为键,并将其值初始化为 1。
这种写法非常适合于计数场景,如统计字符出现的次数,因为它简洁地处理了值的更新和插入。
遍历
只读遍历
// 遍历key
for key in map.keys() {
println!("{key}");
}
// 遍历value
for val in map.values() {
println!("{val}");
}
// 遍历键值对
for (key, val) in map.iter() {
println!("key: {key} val: {val}");
}
into_values() 与 into_keys()
// 可改,但执行完,map就没了,它的所有值已经被移动到迭代器中。开销大,一般不这么用。
// value拥有所有权
for value in map.into_values() {
println!("{}", value);
}
// 常见用法,效果是把所有的val/key放入Vec中。
let mut vec: Vec<i32> = map.into_values().collect();
let mut vec: Vec<&str> = map.into_keys().collect();
vec.sort_unstable(); //排序
注意:遍历的复杂度是O(capacity),而非O(len)
容量、实际长度、判空
assert!(map.capacity() >= 100);
assert_eq!(a.len(), 0);
assert!(!a.is_empty());
导出
for (k, v) in a.drain().take(1) {
assert!(k == 1 || k == 2);
assert!(v == "a" || v == "b");
}
清除
map.clear();
重定容量
// 容量至少增加10
map.reserve(10);
// 尝试容量至少增加10
map.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?");
// 缩小容量至合适大小
map.shrink_to_fit();
// 缩小至(如果参数比len还小,则该句话被忽略)
map.shrink_to(10);