趣味学RUST基础篇(HashMap)

HashMap<K, V>:Rust 里的"魔法储物柜"!

学些HashMap,我们还是举个栗子说明:假设你开了一家超市:

  • 顾客不会说:"我要第三排第二个货架上的东西。"
  • 他们会说:"我要一包蓝龙牌辣条 !" 或者 "来一瓶黄泉牌汽水!"

你总不能靠数货架来找商品吧?你需要一个智能货架系统------

这就是 HashMap 的用武之地!

什么是哈希映射(HashMap)?

HashMap<K, V> 就像一个魔法储物柜:

  • 每个抽屉都有一个标签(Key)
  • 抽屉里放着对应的物品(Value)

比如:

rust 复制代码
"蓝队" → 10 分  
"黄队" → 50 分

你想查蓝队得分?直接问:"蓝队多少分? " → 系统秒回:10!

它不靠"第几个",而是靠"叫什么"来查找,又快又准!


使用前:先开门!

HashMap 不在 Rust 的"默认工具包"里,得先开门:

rust 复制代码
use std::collections::HashMap;

就像你要用特殊保险柜,得先申请权限。


创建一个"魔法储物柜"

1. 新建空柜子

rust 复制代码
let mut scores = HashMap::new();

2. 往里放东西:insert

rust 复制代码
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

现在柜子里有:

复制代码
{
  "Blue": 10,
  "Yellow": 50
}

键(Key)和值(Value)可以是任意类型!

但所有键必须同类型,所有值也必须同类型(同质性)


怎么查东西?用 get 方法!

想查蓝队分数?

rust 复制代码
let team = String::from("Blue");
let score = scores.get(&team);  // 返回 Option<&i32>

注意:

  • get 返回的是 Option<&V>,因为可能没有这个键!
  • 所以你得处理 Some 和 None。

更常见的写法是:

rust 复制代码
let score = scores.get(&team).copied().unwrap_or(0);
// 如果没有,就默认为 0

.copied():把 &i32 变成 i32(因为 i32 可以复制)

.unwrap_or(0):没有就返回 0


遍历所有商品:for 循环

想看看柜子里都有啥?

rust 复制代码
for (team, &score) in &scores {
    println!("{team}: {score}");
}

输出可能是:

text 复制代码
Yellow: 50
Blue: 10

顺序是随机的 !HashMap 不保证顺序(它是哈希的,不是列表)。


所有权规则:放进去了,就归我了!

看这段代码:

rust 复制代码
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 的所有权!

就像你把身份证交给银行办业务,办完前你不能再用它。

解决方案:插入引用

rust 复制代码
map.insert(&name, &value); // 插入引用

但注意:这些引用必须活得比 HashMap 久,否则会变成"悬空指针"!


更新储物柜:三种策略

策略一:直接覆盖(暴力更新)

rust 复制代码
scores.insert("Blue", 25); // 老值 10 被干掉!

简单粗暴,适合"最新值最重要"的场景。


策略二:只在没有时才插入(谨慎更新)

你想加个新队,但不想覆盖旧数据:

rust 复制代码
scores.entry("Red").or_insert(30);
  • 如果 "Red" 没有,就插入 30
  • 如果已有,就不动它

entry() 是 HashMap 的神级 API !

它返回一个"入口"(Entry),你可以用 or_insert、or_insert_with 等方法智能操作。


策略三:基于旧值更新(智能叠加)

最经典的例子:词频统计!

rust 复制代码
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
}

结果:

rust 复制代码
{
  "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> 魔法储物柜 键值对,快速查找
相关推荐
budingxiaomoli1 小时前
Spring统一功能处理
java·后端·spring
eggwyw1 小时前
Anaconda安装卸载的详细流程指南
开发语言·python
某鹏2 小时前
网关选型:Go、Java、Graal 谁都不能完胜
后端
用户0247836530972 小时前
从屎山到防线:14 行状态迁移表,给任务系统装上防瞎跳闸门
后端
CQU_JIAKE2 小时前
11.13[体系结构】指标,五级流水线,八级流水线,虚实地址思考
后端
panbook4 小时前
从0到1实现一个分布式时序数据库(三):主从复制、故障检测与切换
后端
上线再说4 小时前
图片从 8.2MB 压到 296KB:我把小程序图片链路的账单拆了一遍
后端
dpharness4 小时前
我原以为 MCP 装完就能用,直到工具列表是空的
后端
dpharness5 小时前
153 个 MCP 服务,我把工具数一个个数了一遍
后端