Rust学习笔记:集合类型——Vec、String与HashMap

前几篇我们用的都是固定长度的数组和元组。实际开发中,数据量在编译期往往未知——用户列表、文本内容、配置映射……这一篇学习 Rust 三大动态集合类型:Vec(变长数组)、String(文本)和 HashMap(键值对)。


1. Vec:动态数组

Vec<T> 是堆上分配的变长数组。所有元素类型相同。

1.1 创建与基本操作

// 空 Vec
let mut v: Vec<i32> = Vec::new();
v.push(10);
v.push(20);
v.push(30);

// vec! 宏快速创建
let v2 = vec![1, 2, 3, 4, 5];

println!("v = {v:?}, v2 = {v2:?}");
println!("v 长度: {}, 第一个元素: {}", v.len(), v[0]);

1.2 遍历

let v = vec![10, 20, 30, 40, 50];

// 不可变遍历
for elem in &v {
    print!("{elem} ");
}

// 可变遍历
let mut v = vec![1, 2, 3];
for elem in &mut v {
    *elem *= 10;  // * 解引用,修改实际值
}
println!("翻十倍: {v:?}"); // [10, 20, 30]

注意 *elem 的解引用——elem&mut i32 类型,要修改它指向的值就必须先解开引用。

1.3 常用方法

let mut v = vec![1, 2, 3, 4, 5];

// get:安全索引,返回 Option<&T>
v.get(2);   // Some(&3)
v.get(99);  // None——不会 panic

// pop:弹出最后一个
let last = v.pop();  // Some(5)

// insert / remove
v.insert(0, 0);  // [0, 1, 2, 3, 4]
v.remove(2);     // [0, 1, 3, 4]

索引 [] vs get()v[99] 越界会直接 panic;v.get(99) 返回 None。严肃代码优先用 get


2. String:不止是字符串

Rust 的 String 是堆上分配的、可增长的 UTF-8 文本。和 &str(字符串切片、存引用)不同,String 拥有自己的数据。

let mut s = String::from("hello");
s.push_str(", world"); // 追加字符串切片
s.push('!');           // 追加单个字符
println!("{s}");       // hello, world!

2.1 拼接

+ 拼接时,左边的 String 所有权会被拿走:

let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2;  // s1 被移动,s2 是借用
println!("{s3}");
// println!("{s1}"); // ❌ s1 已失效

不想丢所有权,用 format! 宏:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{s1}-{s2}-{s3}"); // 三个都不丢所有权
println!("{s}");
println!("{s1}"); // ✅ 还能用

3. HashMap:键值对

HashMap<K, V> 存一组键值对,键唯一,基于哈希实现。

use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.insert("Bob", 85);

3.1 访问

match scores.get("Alice") {
    Some(score) => println!("Alice 的分数: {score}"),
    None => println!("不存在"),
}

get 返回 Option<&V>,和 Vec::get 一样安全。

3.2 遍历

for (name, score) in &scores {
    println!("{name}: {score}");
}
// 输出顺序不保证

3.3 entry API:更新或插入

这是 HashMap 最常用的模式——根据键是否存在来决定操作:

scores.entry("Alice").or_insert(95);   // Alice 已存在,值不变
scores.entry("Charlie").or_insert(80); // Charlie 不存在,插入 80

3.4 基于旧值更新

entry 返回 Entry 枚举,or_insert 返回值的可变引用,可以基于旧值修改:

let text = "hello world wonderful world";
let mut word_count = HashMap::new();

for word in text.split_whitespace() {
    let count = word_count.entry(word).or_insert(0);
    *count += 1; // 解引用,累加
}
// {"hello": 1, "world": 2, "wonderful": 1}

这个模式在统计、计数场景下非常常用——一行 entry().or_insert() 替代了其他语言里「查键 → 判空 → 更新/插入」的三步曲。


总结

类型 对应 关键操作
Vec<T> 动态数组 push / pop / get / vec![]
String 堆上可增长 UTF-8 字符串 push_str / push / format!
HashMap<K,V> 键值对 insert / get / entry().or_insert()

这三种类型覆盖了日常开发 90% 的数据组织需求。下一篇进入错误处理ResultOption 的实战用法,以及 ? 运算符如何让错误传递简洁优雅。

posted @ 2026-09-19 09:48  PC2005-cloud  阅读(5)  评论(0)    收藏  举报