集合与迭代器¶
📚 章节概述¶
本章将介绍 Rust 标准库中的集合类型和迭代器。集合是存储多个值的数据结构,迭代器提供了一种高效、灵活的处理序列数据的方式。
🎯 学习目标¶
- 掌握 Vec、HashMap、HashSet 等集合类型
- 理解迭代器的概念和使用
- 学会使用迭代器适配器
- 掌握迭代器的性能特性
- 了解不同集合的使用场景
📖 Vector¶
1.1 创建 Vector¶
Rust
fn main() {
// 创建空的 Vec
let v: Vec<i32> = Vec::new(); // Vec<T> 动态数组,存储同类型元素
// 使用 vec! 宏创建
let v = vec![1, 2, 3];
// 指定类型
let v: Vec<i32> = Vec::new();
}
1.2 添加元素¶
Rust
fn main() {
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
println!("{:?}", v);
}
1.3 读取元素¶
Rust
fn main() {
let v = vec![1, 2, 3, 4, 5];
// 使用索引
let third: &i32 = &v[2];
println!("The third element is {}", third);
// 使用 get 方法
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
}
1.4 遍历 Vector¶
Rust
fn main() {
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;
}
println!("{:?}", v);
}
1.5 Vector 的所有权¶
Rust
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
// 获取引用
let first = &v[0];
// 修改 Vector
v.push(6); // 编译错误!不能在存在不可变引用时修改
println!("The first element is: {}", first);
}
1.6 存储不同类型¶
Rust
fn main() {
// 使用枚举存储不同类型
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
}
📚 字符串¶
2.1 String 类型¶
Rust
fn main() {
// 创建空 String
let mut s = String::new();
// 从字面量创建
let s = String::from("hello");
// 使用 to_string
let s = "hello".to_string();
// 使用字符串字面量
let s = String::from("你好");
}
2.2 更新字符串¶
Rust
fn main() {
let mut s = String::from("foo");
s.push_str("bar");
println!("{}", s); // foobar
let mut s = String::from("lo");
s.push('l');
println!("{}", s); // lol
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 注意 s1 被移动了
println!("{}", s3);
}
2.3 格式化字符串¶
Rust
fn main() {
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
println!("{}", s);
}
2.4 字符串切片¶
Rust
fn main() {
let hello = "Здравствуйте";
let s = &hello[0..4]; // 注意:不是字符数,是字节数
println!("{}", s);
}
2.5 遍历字符串¶
Rust
fn main() {
for c in "नमस्ते".chars() {
println!("{}", c);
}
for b in "नमस्ते".bytes() {
println!("{}", b);
}
}
🗺️ HashMap¶
3.1 创建 HashMap¶
Rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new(); // HashMap 键值对集合,O(1)查找
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
println!("{:?}", scores);
}
3.2 访问值¶
Rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name);
match score {
Some(s) => println!("Score: {}", s),
None => println!("Team not found"),
}
}
3.3 遍历 HashMap¶
Rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
for (key, value) in &scores {
println!("{}: {}", key, value);
}
}
3.4 更新 HashMap¶
Rust
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
// 覆盖旧值
scores.insert(String::from("Blue"), 25);
// 只在键不存在时插入
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);
}
3.5 根据旧值更新¶
Rust
use std::collections::HashMap;
fn main() {
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); // 返回&mut V(值的可变引用),键不存在则插入0
*count += 1; // 解引用可变引用后修改HashMap中的值
}
println!("{:?}", map);
}
🔄 迭代器¶
4.1 创建迭代器¶
Rust
fn main() {
let mut v = vec![1, 2, 3];
// 不可变引用迭代器
for val in v.iter() {
println!("{}", val);
}
// 可变引用迭代器(需要 mut)
for val in v.iter_mut() {
*val += 1;
}
// 获取所有权(之后 v 不再可用)
let into_iter = v.into_iter();
for val in into_iter {
println!("{}", val);
}
}
4.2 使用迭代器¶
Rust
fn main() {
let v = vec![1, 2, 3];
// 使用 for 循环
for val in v.iter() {
println!("{}", val);
}
// 使用 next 方法
let mut iter = v.iter();
let val = iter.next();
println!("{:?}", val); // Some(&1)
}
4.3 迭代器适配器¶
Rust
fn main() {
let v1 = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); // |x| 闭包语法,捕获环境变量
println!("{:?}", v2); // [2, 3, 4]
}
4.4 常用迭代器方法¶
Rust
fn main() {
let v = vec![1, 2, 3, 4, 5];
// map
let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();
println!("{:?}", doubled);
// filter
let evens: Vec<&i32> = v.iter().filter(|&x| x % 2 == 0).collect();
println!("{:?}", evens);
// fold
let sum: i32 = v.iter().fold(0, |acc, x| acc + x);
println!("Sum: {}", sum);
// any/all
let has_even = v.iter().any(|&x| x % 2 == 0);
let all_positive = v.iter().all(|&x| x > 0);
println!("Has even: {}, All positive: {}", has_even, all_positive);
}
4.5 消费适配器¶
Rust
fn main() {
let v = vec![1, 2, 3, 4, 5];
// sum
let sum: i32 = v.iter().sum();
println!("Sum: {}", sum);
// collect
let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();
println!("{:?}", doubled);
// find
let found = v.iter().find(|&&x| x > 3);
println!("Found: {:?}", found);
// count
let count = v.iter().count();
println!("Count: {}", count);
}
📝 练习题¶
练习 1:Vector 操作¶
Rust
// TODO: 实现以下功能
// 1. 创建一个包含 1-10 的 Vector
// 2. 过滤出偶数
// 3. 将每个偶数乘以 2
// 4. 计算最终的和
fn main() {
// TODO: 实现
}
练习 2:字符串处理¶
Rust
// TODO: 实现一个函数,统计字符串中每个字符的出现次数
fn char_count(s: &str) -> HashMap<char, usize> {
// TODO: 实现
todo!()
}
fn main() {
let s = "hello world";
println!("{:?}", char_count(s));
}
练习 3:HashMap 操作¶
Rust
use std::collections::HashMap;
// TODO: 实现一个函数,合并两个 HashMap
// 如果键冲突,保留较大的值
fn merge_maps(map1: HashMap<&str, i32>, map2: HashMap<&str, i32>) -> HashMap<&str, i32> {
// TODO: 实现
todo!()
}
fn main() {
let mut map1 = HashMap::new();
map1.insert("a", 1);
map1.insert("b", 2);
let mut map2 = HashMap::new();
map2.insert("b", 3);
map2.insert("c", 4);
println!("{:?}", merge_maps(map1, map2));
}
练习 4:迭代器链¶
Rust
// TODO: 使用迭代器实现以下功能
// 1. 生成 1-100 的数字
// 2. 过滤出能被 3 或 5 整除的数
// 3. 将这些数平方
// 4. 取前 10 个
// 5. 计算它们的和
fn main() {
// TODO: 实现
}
💡 最佳实践¶
1. 选择合适的集合类型¶
Rust
// Vec: 需要动态大小、按索引访问
let v = vec![1, 2, 3];
// HashMap: 需要键值对查找
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("key", "value");
// HashSet: 需要唯一值、快速查找
use std::collections::HashSet;
let set: HashSet<i32> = vec![1, 2, 3, 2, 1].into_iter().collect();
2. 使用迭代器而不是循环¶
Rust
// 好
let sum: i32 = v.iter().sum();
let evens: Vec<i32> = v.iter().filter(|x| x % 2 == 0).cloned().collect();
// 避免
let mut sum = 0;
for x in &v {
sum += x;
}
3. 函数参数优先使用 &str¶
Rust
// 好:不需要所有权时接受 &str
fn process(s: &str) {
println!("{}", s);
}
// 避免:不必要地要求 String 所有权
fn process_owned(s: String) {
// 强制调用者放弃所有权或克隆
println!("{}", s);
}
4. 使用 entry API 更新 HashMap¶
Rust
// 好
scores.entry(team_name).or_insert(0);
// 避免
if !scores.contains_key(&team_name) {
scores.insert(team_name.clone(), 0);
}
⚠️ 常见错误¶
1. Vector 索引越界¶
Rust
// 错误(运行时 panic)
let v = vec![1, 2, 3];
let x = v[10];
// 正确
let v = vec![1, 2, 3];
let x = v.get(10).unwrap_or(&0);
2. 字符串切片错误¶
Rust
// 错误(可能在字符中间切割)
let s = "你好";
let sub = &s[0..1]; // 可能 panic
// 正确
let s = "你好";
let sub = s.chars().next().unwrap();
3. HashMap 键的类型¶
Rust
// 可以编译(通过 Deref 强制转换),但有多余的 String 分配
let mut map = HashMap::new();
map.insert("key", "value");
let value = map.get(&String::from("key")); // 可行,但不必要
// 更好:直接使用 &str
let mut map = HashMap::new();
map.insert("key", "value");
let value = map.get("key");
📚 扩展阅读¶
🎯 本章小结¶
本章介绍了 Rust 的集合和迭代器:
- ✅ 掌握 Vec、HashMap、HashSet 等集合类型
- ✅ 理解迭代器的概念和使用
- ✅ 学会使用迭代器适配器
- ✅ 掌握迭代器的性能特性
- ✅ 了解不同集合的使用场景
下一章: 我们将学习 Rust 的模块系统和包管理,包括模块、use 关键字和 Cargo 依赖管理。