好主意。HashMap 和 HashSet 是 Rust 最核心的标准库容器之一,而且很多 Rust 代码都会围绕它们写。如果你打算系统试一遍,我建议按 结构 → 常用方法 → 进阶 API → 迭代器 → 实用技巧 这样理解,会非常清晰。
它们都在:
use std::collections::{HashMap, HashSet};
本质上:
HashMap<K, V>:键值对HashSet<T>:只有键(本质上是HashMap<T, ()>)
一、HashMap 结构
HashMap<K, V>
要求:
K: Eq + Hash
因为要进行哈希比较。
例子:
use std::collections::HashMap;
let mut map: HashMap<String, i32> = HashMap::new();
二、HashMap 创建方法
1 new
let map: HashMap<i32, i32> = HashMap::new();
2 with_capacity
提前分配空间。
let map: HashMap<i32, i32> = HashMap::with_capacity(100);
减少 rehash。
3 from
let map = HashMap::from([
("a", 1),
("b", 2),
]);
三、HashMap 基本操作
1 插入 insert
map.insert("apple", 3);
返回:
Option<V>
如果 key 已存在:
let old = map.insert("apple", 5);
old = Some(3)
2 获取 get
map.get("apple")
返回:
Option<&V>
例子:
if let Some(v) = map.get("apple") {
println!("{}", v);
}
3 获取可变值 get_mut
map.get_mut("apple")
返回:
Option<&mut V>
例子:
if let Some(v) = map.get_mut("apple") {
*v += 1;
}
4 删除 remove
map.remove("apple")
返回:
Option<V>
5 是否包含 key
map.contains_key("apple")
返回:
bool
四、Entry API(Rust最强HashMap接口)
Rust 的 HashMap 最强 API 是 entry()。
它避免:
- 先查
- 再插入
这种两次查找。
1 entry
map.entry("apple")
返回:
Entry<K,V>
有两种:
Occupied
Vacant
2 or_insert
map.entry("apple").or_insert(0);
含义:
如果没有 -> 插入0
如果有 -> 返回已有值
返回:
&mut V
例子:
*map.entry("apple").or_insert(0) += 1;
经典 词频统计:
for word in words {
*map.entry(word).or_insert(0) += 1;
}
3 or_insert_with
延迟计算。
map.entry("key").or_insert_with(|| expensive());
只有需要时才计算。
4 and_modify
map.entry("apple")
.and_modify(|v| *v += 1)
.or_insert(1);
意思:
如果存在 -> 修改
如果不存在 -> 插入
非常常用。
五、HashMap 遍历
1 遍历 key value
for (k, v) in &map {
println!("{} {}", k, v);
}
类型:
(&K, &V)
2 只遍历 key
for k in map.keys() {
}
3 只遍历 value
for v in map.values() {
}
4 可变 value
for v in map.values_mut() {
*v += 1;
}
六、HashMap 容量操作
len
map.len()
is_empty
map.is_empty()
clear
map.clear()
删除全部。
capacity
map.capacity()
reserve
map.reserve(100);
增加容量。
shrink_to_fit
map.shrink_to_fit();
释放多余空间。
七、HashMap 进阶 API
remove_entry
删除并返回 key value
map.remove_entry("apple")
返回:
Option<(K,V)>
retain
过滤元素
map.retain(|k, v| *v > 10);
drain
清空并返回迭代器
for (k, v) in map.drain() {
}
八、HashSet
HashSet 本质:
HashMap<T, ()>
所以 API 很类似。
九、HashSet 创建
use std::collections::HashSet;
let mut set = HashSet::new();
from
let set = HashSet::from([1,2,3]);
with_capacity
HashSet::with_capacity(100);
十、HashSet 基本操作
insert
set.insert(10);
返回:
bool
是否新插入。
contains
set.contains(&10);
remove
set.remove(&10);
len
set.len()
clear
set.clear()
十一、HashSet 集合运算(非常强)
union
并集
set1.union(&set2)
intersection
交集
set1.intersection(&set2)
difference
差集
set1.difference(&set2)
symmetric_difference
对称差
set1.symmetric_difference(&set2)
例子:
for x in set1.intersection(&set2) {
println!("{}", x);
}
十二、HashSet 遍历
for v in &set {
println!("{}", v);
}
十三、HashSet 关系判断
is_subset
set1.is_subset(&set2)
is_superset
set1.is_superset(&set2)
is_disjoint
set1.is_disjoint(&set2)
两个集合是否没有交集。
十四、一个典型例子
去重
let nums = vec![1,2,2,3,4];
let set: HashSet<_> = nums.into_iter().collect();
统计词频
let mut map = HashMap::new();
for word in text.split_whitespace() {
*map.entry(word).or_insert(0) += 1;
}
十五、Rust HashMap 一个隐藏知识
Rust标准库 HashMap 不是自己实现的。
它使用:
SwissTable
来自:
算法实现来自:
Abseil
特点:
- SIMD 查找
- robin hood hashing
- 非常快