趣味学RUST基础篇(HashMap)
HashMap<K, V>
:Rust 里的“魔法储物柜”!
学些HashMap,我们还是举个栗子说明:假设你开了一家超市:
- 顾客不会说:“我要第三排第二个货架上的东西。”
- 他们会说:“我要一包蓝龙牌辣条!” 或者 “来一瓶黄泉牌汽水!”
你总不能靠数货架来找商品吧?你需要一个智能货架系统——
这就是 HashMap
的用武之地!
什么是哈希映射(HashMap)?
HashMap<K, V>
就像一个魔法储物柜:
- 每个抽屉都有一个标签(Key)
- 抽屉里放着对应的物品(Value)
比如:
"蓝队" → 10 分
"黄队" → 50 分
你想查蓝队得分?直接问:“蓝队多少分?” → 系统秒回:10
!
它不靠“第几个”,而是靠“叫什么”来查找,又快又准!
使用前:先开门!
HashMap
不在 Rust 的“默认工具包”里,得先开门:
use std::collections::HashMap;
就像你要用特殊保险柜,得先申请权限。
创建一个“魔法储物柜”
1. 新建空柜子
let mut scores = HashMap::new();
2. 往里放东西:insert
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
现在柜子里有:
{"Blue": 10,"Yellow": 50
}
键(Key)和值(Value)可以是任意类型!
但所有键必须同类型,所有值也必须同类型(同质性)
怎么查东西?用 get
方法!
想查蓝队分数?
let team = String::from("Blue");
let score = scores.get(&team); // 返回 Option<&i32>
注意:
get
返回的是Option<&V>
,因为可能没有这个键!- 所以你得处理
Some
和None
。
更常见的写法是:
let score = scores.get(&team).copied().unwrap_or(0);
// 如果没有,就默认为 0
.copied()
:把&i32
变成i32
(因为i32
可以复制)
.unwrap_or(0)
:没有就返回 0
遍历所有商品:for
循环
想看看柜子里都有啥?
for (team, &score) in &scores {println!("{team}: {score}");
}
输出可能是:
Yellow: 50
Blue: 10
顺序是随机的!
HashMap
不保证顺序(它是哈希的,不是列表)。
所有权规则:放进去了,就归我了!
看这段代码:
let name = String::from("Favorite color");
let value = String::from("Blue");let mut map = HashMap::new();
map.insert(name, value);println!("{}", name); // 编译错误!
为什么?因为 insert
拿走了 name
和 value
的所有权!
就像你把身份证交给银行办业务,办完前你不能再用它。
解决方案:插入引用
map.insert(&name, &value); // 插入引用
但注意:这些引用必须活得比 HashMap
久,否则会变成“悬空指针”!
更新储物柜:三种策略
策略一:直接覆盖(暴力更新)
scores.insert("Blue", 25); // 老值 10 被干掉!
简单粗暴,适合“最新值最重要”的场景。
策略二:只在没有时才插入(谨慎更新)
你想加个新队,但不想覆盖旧数据:
scores.entry("Red").or_insert(30);
- 如果
"Red"
没有,就插入30
- 如果已有,就不动它
entry()
是HashMap
的神级 API!
它返回一个“入口”(Entry),你可以用or_insert
、or_insert_with
等方法智能操作。
策略三:基于旧值更新(智能叠加)
最经典的例子:词频统计!
let text = "hello world hello rust world";let mut word_count = HashMap::new();for word in text.split_whitespace() {let count = word_count.entry(word).or_insert(0);*count += 1; // 解引用后 +1
}
结果:
{"hello": 2,"world": 2,"rust": 1
}
关键点:
or_insert(0)
返回&mut i32
(可变引用)- 用
*count += 1
修改它- 引用在循环结束时自动释放,安全!
哈希函数:柜子背后的“分拣机器人”
HashMap
为什么这么快?因为它用哈希函数把钥匙(Key)变成“抽屉编号”。
Rust 默认用 SipHash:
- 安全:防黑客攻击(防止“哈希碰撞攻击”)
- 稍慢:不是最快的算法
如果你发现性能瓶颈,可以换更快的 hasher(比如 ahash
),但一般没必要。
想换?去 crates.io 找找看!
小结:HashMap
使用口诀
操作 | 方法 |
---|---|
创建 | HashMap::new() |
插入 | insert(key, value) |
查询 | get(&key) → 返回 Option<&V> |
遍历 | for (k, v) in &map |
智能插入 | entry(key).or_insert(value) |
词频统计 | *entry(key).or_insert(0) += 1 |
所有权 | 值会被 move,引用需注意生命周期 |
三神器合体:Rust 冒险者工具箱
容器 | 别名 | 适用场景 |
---|---|---|
Vec<T> | 魔法背包 | 有序列表,按索引访问 |
String | 魔法卷轴 | 存文本,支持 UTF-8 |
HashMap<K,V> | 魔法储物柜 | 键值对,快速查找 |