集合类型
Vec、String、HashMap、Box/Rc/Arc 概览。
集合类型
这一课你将能做到
- 熟练操作 Vec、String、HashMap 三大集合,理解「所有权跟着集合走」
- 区分 iter / iter_mut / into_iter 三种遍历,知道集合遍历时为什么不能顺手修改
- 用迭代器适配器链(map/filter/collect)写出零开销的数据管道
为什么要学
Java 工程师每天离不开 ArrayList、HashMap、Stream——Rust 对应的是 Vec、HashMap 和迭代器。区别在于:Java 的 Stream 是运行时构建的惰性流水线,Rust 的迭代器链编译期直接展开成手写循环级别的机器码(零成本抽象的招牌案例)。
判题系统里到处是集合操作:提交队列(Vec)、判题结果缓存(HashMap)、拼接评测输出(String)。这一课的场景全部围绕它们展开。
先建立图像
Java Rust
ArrayList<T> ↔ Vec<T> 堆上连续内存,随机访问 O(1)
HashMap<K,V> ↔ HashMap<K,V> 哈希表(Rust 默认 SipHash,防 HashDoS)
String / StringBuilder ↔ String UTF-8 堆上可增长
Stream<T> ↔ Iterator trait 惰性管道,但编译期单态化
三个集合全部把数据存在堆上、变量持有所有权——所有权规则在这里全面生效:move 集合就是把整块堆数据易主,遍历借用要 &。
跟着做
步骤 1:Vec——最常用的动态数组
cargo new coll-demo
cd coll-demo
fn main() {
let mut queue: Vec<String> = Vec::new(); // 或 vec!["s1".into(), "s2".into()]
queue.push("submit-1".to_string()); // 尾部入队
queue.push("submit-2".to_string());
queue.push("submit-3".to_string());
let first = queue.remove(0); // 取出并移除下标 0(所有权转移出来)
println!("处理 {first},队列剩余 {:?}", queue);
let peek = &queue[0]; // 借用访问:越界直接 panic
let safe = queue.get(99); // Option 访问:越界返回 None
println!("队首 {peek},越界查询 {:?}", safe);
}
背下这组对照:v[i] 索引访问(越界 panic,对标 Java ArrayIndexOutOfBounds)、v.get(i) 安全访问(Option)、v.remove(i) 取走元素(所有权移出)。
步骤 2:三种遍历——所有权决定写法
fn main() {
let mut times = vec![120u32, 990, 1500, 80];
for t in × { // iter():不可变借用,集合还在
println!("{t}");
}
for t in &mut times { // iter_mut():可变借用,能改元素
*t = t.saturating_sub(100);
}
let owned: Vec<u32> = times.clone().into_iter().filter(|&t| t > 0).collect();
println!("{:?} / {:?}", times, owned);
}
× 借用读、&mut times 借用写、into_iter() 拿走集合所有权逐个交出元素。想在遍历中删元素?编译器直接拒绝(迭代器持有借用)——Java 的 ConcurrentModificationException 变成编译错误。