← [ BACK_TO_NOTES ]

Rust 集合:Vec 与 HashMap

Vec 动态数组与 HashMap 哈希表的所有权接口、常用操作、迭代与工程注意点。

#concept #growing #dev #rust

[!info] related notes

Rust 集合:Vec 与 HashMap

这个概念为什么出现

固定数组不够用时,需要:

  • 可增长列表:Vec<T>
  • 键值索引:HashMap<K,V>

它们是 std 集合的主干,接口全面贯彻所有权与借用。

[!abstract] 一句话理解 Vec<T> 是堆上连续可增长数组;HashMap<K,V> 是哈希键值表;索引/插入/删除的 API 通过所有权与借用表达“拿走还是看一眼”。

最小可运行示例

场景:购物车 SKU 列表 + 优惠券核销表

结算前:购物车是 Vec;HashMap 仅演示单进程内的优惠券占位。真实核销跨请求/进程的唯一性与持久化需要数据库或其他一致性机制。

use std::collections::HashMap;

// 业务意图:维护购物车行项目与优惠券占用。
// 教学点:Vec push/iter;HashMap entry;所有权 insert。

fn main() {
    let mut cart: Vec<String> = Vec::new();
    cart.push(String::from("sku-apple"));
    cart.push(String::from("sku-milk"));

    let mut redeemed: HashMap<String, u32> = HashMap::new();
    // entry API:不存在则插入
    redeemed.entry(String::from("OFF10")).or_insert(1);

    println!("cart_len={}", cart.len());
    for sku in &cart {
        // 借用迭代,不 move 出 Vec
        println!("sku={sku}");
    }
    println!("off10={}", redeemed.get("OFF10").unwrap());
}

建议运行:cargo run

期望输出:

cart_len=2
sku=sku-apple
sku=sku-milk
off10=1

结合场景再看三个关注点

  1. for sku in &cart 借用元素并保留 cart;按值迭代是消耗 Vec,不是留下一个可继续用的空 Vec
  2. entry 优雅处理“首次插入”
  3. 键和值的所有权:传值会移动非 Copy 的 String;借用查询 get 不转移键的所有权

核心概念与准确模型

Vec

  • push/pop/len/capacity
  • 索引 v[i] 越界 panic;get 返回 Option
  • 可 as_slice() 变成 &[T]

HashMap

  • 键需实现 Eq + Hash
  • get 返回 Option<&V>
  • 迭代顺序默认不保证(除非用特殊 map)

所有权模式

API典型效果
push(T)拿走 T
iter()借 &T
拥有的 Vec / HashMap 上 into_iter()消耗集合,按值产出元素;引用上的 IntoIterator 则产出借用
remove返回拥有的值

设计动机

  • 动态集合是系统编程刚需
  • API 与借用检查一致,避免迭代时修改等未定义行为
  • 与迭代器生态深度整合

边界与误区

  • 从 Vec 借出的引用仍被后续使用时,不能对同一 Vec 调用 push;扩容可能移动缓冲区。即使预留足够 capacity,也不会放宽此借用规则
  • HashMap 查找用借用键:map.get("OFF10") 可因 Borrow 工作
  • with_capacity 预留容量但长度仍为 0,不能立即索引写入未初始化元素;需要 push 或 resize
  • 示例 unwrap 依赖此前已插入 OFF10;不确定键是否存在时应处理 None

[!warning] 常见误区:for x in vec 之后还想用 vec for x in vec 是 into_iter,会搬走;用 for x in &vec。

工程实践

  1. 热路径预估 capacity
  2. 公共 API 返回切片/迭代器而不是强制 Vec 若只需读
  3. 键类型稳定且哈希成本可控
  4. 需要排序映射用 BTreeMap

本节总结

  • Vec 管列表,HashMap 管关联
  • 迭代方式决定是否 move
  • entry API 处理占位插入

自测题

  1. v.get(i) 与 v[i] 差别?
  2. 为什么 HashMap 键常要拥有?
参考答案
  1. get 返回 Option,[] 越界 panic。
  2. map 需要在自己生命周期内持有键;也可用引用键但需生命周期。

延伸阅读与资料来源

资料类型支撑内容
The Book — Common Collections官方书Vec/String/HashMap
std::vec::Vec标准库Vec
std::collections::HashMap标准库HashMap
创建于 2026/7/15 更新于 2026/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本