Rust HashMap:插入、查找与 entry API
更新时间:2026-09-20。
HashMap是最常用的键值集合,底层是罗宾汉开放寻址(非链表桶)。Vec的内存布局见 Vec/String 内存布局,集合选型见 常用集合怎么选。
一、基本增删查
rust
use std::collections::HashMap;
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert(String::from("blue"), 10);
scores.insert(String::from("red"), 50);
if let Some(v) = scores.get("blue") { // get 返回 Option<&V>
println!("{v}");
}
for (k, v) in &scores { println!("{k}={v}"); }
scores.remove("red");get 返回 Option<&V> 而不是直接给值,查不到是 None 而非崩溃。key 类型必须实现 Eq + Hash(整数、String、&str 都满足)。
二、entry API:计数 / upsert 的正确姿势
统计词频最典型。新手会先 get 再 insert,查两次还撞借用检查;entry 一次搞定:
rust
let mut count: HashMap<&str, u32> = HashMap::new();
for word in ["a", "b", "a", "c", "b", "a"] {
*count.entry(word).or_insert(0) += 1; // 有就取 &mut,没有就插 0
}
assert_eq!(count["a"], 3);
// 已存在才改、不存在才插的组合
count.entry("d")
.and_modify(|v| *v += 1)
.or_insert(1);| API | 作用 |
|---|---|
or_insert(v) | 空位插入 v,返回 &mut V |
or_default() | 空位插入类型默认值(数字为 0) |
or_insert_with(f) | 惰性构造,避免无谓分配 |
and_modify(f) | 键存在时对其值执行 f,可链式接 or_insert |
三、所有权:String 与 &str 作 key
rust
let mut m = HashMap::new();
let name = String::from("alice");
m.insert(name, 20); // String 被 move 进 map,之后 name 不可用
// m.insert(&name, 20); // 若只借 &str,则 name 必须活得比 map 久
m.insert("bob".to_string(), 30);
let x = m.get("alice"); // 用 &str 查 String key:Borrow 自动适配HashMap<String, V> 可以直接用 &str 调 get,靠的是 Borrow<str>,无需把查询串转成 String。
四、容量与迭代顺序
rust
let mut m: HashMap<i32, i32> = HashMap::with_capacity(1000); // 已知规模,预留HashMap迭代顺序随机、不保证(RandomState 还带每进程随机种子,防哈希碰撞攻击);需要有序用BTreeMap。- 预估条数用
with_capacity,避免反复 rehash。
五、常见坑
- 循环里持有
&V又 insert:可变借用与不可变借用冲突编译失败;先把要用的值 clone 出来或用entry。 get后 unwrap:键不确定就if let/match,确定存在才用scores["k"](缺失会 panic)。- 计数写成 get+insert:查两次且啰嗦,统一
entry().or_insert(0)。 - 依赖遍历顺序:HashMap 随机序,要排序遍历 key 用
BTreeMap或自行收集排序。 - 多线程共享普通 HashMap:会编译失败/数据竞争,并发用
DashMap或套Mutex<HashMap>(见 Arc/Mutex/RwLock)。
总结
Rust HashMap 用 new/insert/get(返回 Option<&V>)操作,key 必须 Eq+Hash、底层开放寻址且遍历顺序随机,已知规模用 with_capacity 预留;计数和「存在则改、不存在则插」一律用 entry().or_insert/and_modify,避免 get 后再 insert 的二次查找与借用冲突;String key 会拿走所有权但可用 &str 经 Borrow 查询,多线程共享不能用裸 HashMap,要套 Mutex/RwLock 或用 DashMap。