目录
[04 集合类型](#04 集合类型)
[4.1 Vector(动态数组)](#4.1 Vector(动态数组))
[所有权与 Vector](#所有权与 Vector)
[4.2 字符串(String)](#4.2 字符串(String))
[Rust 字符串类型全景](#Rust 字符串类型全景)
[String 内部结构](#String 内部结构)
[4.3 哈希 Map(HashMap)](#4.3 哈希 Map(HashMap))
[更新 HashMap](#更新 HashMap)
[4.4 三大集合对比](#4.4 三大集合对比)
04 集合类型
4.1 Vector(动态数组)
创建与基本操作
rust
// 创建
let mut v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3]; // 宏创建并初始化
// 添加元素
let mut v = Vec::new();
v.push(5);
v.push(6);
// 读取元素
let third = &v[2]; // 索引访问(越界会 panic)
let third = v.get(2); // 返回 Option<&T>(安全访问)
match v.get(100) {
Some(value) => println!("第100个是: {value}"),
None => println!("没有第100个元素"),
}
遍历
rust
let v = vec![100, 32, 57];
// 不可变遍历
for i in &v {
println!("{i}");
}
// 可变遍历
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50; // 解引用后修改
}
所有权与 Vector
rust
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
// Vec 存储 heterogeneous 数据:枚举是标准方案
// 切片
let slice = &v[0..2]; // &[i32] 类型
let slice = &v[..]; // 整个 vector 的切片
常用方法速查
|-------------------|-------------------------------------------|----------------------|
| 方法 | 签名 | 说明 |
| push | fn push(&mut self, value: T) | 末尾添加 |
| pop | fn pop(&mut self) -> Option<T> | 弹出末尾元素 |
| remove | fn remove(&mut self, index: usize) -> T | 按索引移除 |
| len | fn len(&self) -> usize | 长度 |
| is_empty | fn is_empty(&self) -> bool | 是否为空 |
| contains | fn contains(&self, x: &T) -> bool | 是否包含(需 T: PartialEq) |
| sort | fn sort(&mut self) | 排序(需 T: Ord) |
| dedup | fn dedup(&mut self) | 去除连续重复 |
| clear | fn clear(&mut self) | 清空 |
| with_capacity | fn with_capacity(cap: usize) -> Vec<T> | 预分配容量 |
4.2 字符串(String)
Rust 字符串类型全景
|---------------------|-----------------------------|-------------|
| 类型 | 说明 | 使用场景 |
| String | 堆上分配,可增长,UTF-8 编码 | 运行时动态字符串 |
| &str**(字符串切片)** | 栈上(ptr + len),指向某处 UTF-8 数据 | 函数参数、字符串字面量 |
| str | 切片类型(unsized),不能直接使用 | 类型系统底层 |
| Cow
创建字符串
rust
let mut s = String::new(); // 空 String
let s = String::from("hello"); // 从 &str 创建
let s = "hello".to_string(); // 从 &str 创建(通过 Display trait)
let s = String::from("你好"); // UTF-8 支持
let s = format!("{}-{}", "hello", "world"); // format! 宏
更新字符串
rust
let mut s = String::from("foo");
s.push_str("bar"); // 追加 &str
s.push('l'); // 追加单个 char
// 使用 + 运算符(注意所有权)
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1 被移动,s2 被借用
// + 实际上调用了 fn add(self, &str) -> String
// format! 宏(不获取所有权)
let s = format!("{}-{}", s2, "!!!"); // s2 仍然有效
索引字符串
rust
let s = String::from("hello");
// let h = s[0]; // 编译错误!String 不支持索引(因为 UTF-8)
let s = String::from("你好");
// let h = &s[0..1]; // 运行时 panic!'你' 占 3 字节
let h = &s[0..3]; // OK,"你"
// 正确遍历:chars(Unicode 标量值)或 bytes(原始字节)
for c in "नमस्ते".chars() {
println!("{c}"); // 输出每个 Unicode 字符
}
for b in "नमस्ते".bytes() {
println!("{b}"); // 输出每个 UTF-8 字节
}
String 内部结构
String(栈上):
┌──────────┬─────┬───────────┐
│ ptr ────→│ len │ capacity │
└──────────┴─────┴───────────┘
5 bytes 5 bytes
堆上数据(UTF-8 编码):
┌───┬───┬───┬───┬───┐
│ h │ e │ l │ l │ o │
└───┴───┴───┴───┴───┘
0 1 2 3 4
常用方法速查
|------------------------------------------------------|---------------------------------|
| 方法 | 说明 |
| len() | 返回字节数(非字符数!) |
| is_empty() | 是否为空 |
| push_str() | 追加 &str |
| push() | 追加 char |
| trim()****/ trim_start()****/ trim_end() | 去除空白 |
| split_whitespace() | 按空白分割(返回迭代器) |
| split() | 按模式分割 |
| contains() | 是否包含子串 |
| replace() | 替换 |
| to_lowercase()****/ to_uppercase() | 大小写转换 |
| as_str() | 转为 &str |
| into_bytes() | 消费 String,返回 Vec<u8> |
| from_utf8() | 从 Vec<u8> 创建 Result<String> |
4.3 哈希 Map(HashMap)
创建与基本操作
rust
use std::collections::HashMap;
// 创建
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
// 用 zip + collect 创建
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.into_iter().zip(initial_scores.into_iter()).collect();
访问值
rust
let team_name = String::from("Blue");
let score = scores.get(&team_name); // 返回 Option<&V>
// 遍历
for (key, value) in &scores {
println!("{}: {}", key, value);
}
更新 HashMap
rust
// 1. 覆盖旧值
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25); // 覆盖为 25
// 2. 仅当 key 不存在时插入
scores.entry(String::from("Blue")).or_insert(50);
// entry 返回 Entry 枚举,or_insert 在 Vacant 时插入
// 3. 基于旧值更新
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1; // 解引用修改
}
// {"world": 2, "hello": 1, "wonderful": 1}
所有权
rust
// key 和 value 被移动到 HashMap 中
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name 和 field_value 已失效
// 使用引用(需要生命周期)
fn hash_map_example() {
let mut map: HashMap<&str, &str> = HashMap::new();
map.insert("key", "value");
}
常用方法速查
|------------------------------|--------------------------|
| 方法 | 说明 |
| insert(k, v) | 插入键值对(返回 Option<V>:旧值) |
| get(&k) | 获取值,返回 Option<&V> |
| remove(&k) | 删除,返回 Option<V> |
| contains_key(&k) | 是否包含 key |
| len() | 键值对数量 |
| is_empty() | 是否为空 |
| entry(k) | 获取 Entry(用于条件插入) |
| keys()****/ values() | 遍历所有 key / value |
| iter() | 遍历 (&K, &V) 引用 |
| clear() | 清空 |
| with_capacity(n) | 预分配容量 |
4.4 三大集合对比
|------------------|-------------------------|----------------------------|-----------------------------|
| 特性 | Vec\<T\> | String | HashMap\<K, V\> |
| 内部表示 | 连续内存(堆) | UTF-8 字节序列(堆) | 哈希桶(堆) |
| 增长策略 | 自动扩容(2x) | 自动扩容 | 自动扩容 |
| 索引 | O(1) | O(1) 按字节(不安全) | N/A |
| 查找 | O(n) 线性 / O(log n) 排序后 | 子串查找 O(n) | O(1) 平均 |
| 迭代 | 有序 | 有序(字节) | 无序(不保证遍历顺序) |
| Clone 花费 | O(n) | O(n) | O(n) |
| 预分配 | Vec::with_capacity(n) | String::with_capacity(n) | HashMap::with_capacity(n) |
学习目标检验
- 能使用
vec!宏创建 Vector,并 push/pop 遍历 - 理解
Stringvs&str的区别和使用场景 - 知道为什么不能直接索引 String,理解 UTF-8
- 能使用
HashMap::new()、insert、get、entry().or_insert() - 理解 HashMap 无序的特性
- 知道何时预分配容量以提高性能