迭代器基础(Iterator Basics)
迭代器是 Rust 中处理数据集合的强大工具。它们提供了一种函数式编程的方式来处理数据,具有惰性求值、零成本抽象等特性。
什么是迭代器?
迭代器是一个实现了 Iterator trait 的类型,它可以:
- 逐个产生元素
- 惰性求值:只在需要时计算
- 可组合:可以链式调用多个操作
- 零成本抽象:编译时优化为高效的循环
Iterator Trait
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 默认实现的方法
fn size_hint(&self) -> (usize, Option<usize>) { (0, None) }
fn count(self) -> usize { ... }
fn map<B, F>(self, f: F) -> Map<Self, F> { ... }
fn filter<P>(self, predicate: P) -> Filter<Self, P> { ... }
// ... 更多方法
}
创建迭代器
从集合创建
fn main() {
let vec = vec![1, 2, 3, 4, 5];
// iter() - 创建不可变引用的迭代器
let iter1 = vec.iter();
for item in iter1 {
println!("引用: {}", item); // item 是 &i32
}
// iter_mut() - 创建可变引用的迭代器
let mut vec2 = vec![1, 2, 3, 4, 5];
let iter2 = vec2.iter_mut();
for item in iter2 {
*item *= 2; // item 是 &mut i32
}
println!("修改后: {:?}", vec2);
// into_iter() - 创建拥有所有权的迭代器
let vec3 = vec![1, 2, 3, 4, 5];
let iter3 = vec3.into_iter();
for item in iter3 {
println!("拥有: {}", item); // item 是 i32
}
// vec3 已经被移动,不能再使用
}
范围迭代器
fn main() {
// 范围迭代器
for i in 0..5 {
println!("数字: {}", i);
}
// 包含结束值的范围
for i in 0..=5 {
println!("包含结束: {}", i);
}
// 收集到向量
let numbers: Vec<i32> = (1..10).collect();
println!("收集的数字: {:?}", numbers);
// 步长迭代
let even_numbers: Vec<i32> = (0..10).step_by(2).collect();
println!("偶数: {:?}", even_numbers);
}
自定义迭代器
struct Counter {
current: usize,
max: usize,
}
impl Counter {
fn new(max: usize) -> Counter {
Counter { current: 0, max }
}
}
impl Iterator for Counter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.max {
let current = self.current;
self.current += 1;
Some(current)
} else {
None
}
}
}
fn main() {
let counter = Counter::new(5);
for num in counter {
println!("计数: {}", num);
}
// 使用迭代器方法
let sum: usize = Counter::new(5).sum();
println!("总和: {}", sum);
}
迭代器适配器
适配器将一个迭代器转换为另一个迭代器,它们是惰性的。
map - 转换元素
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// 将每个数字平方
let squares: Vec<i32> = numbers
.iter()
.map(|x| x * x)
.collect();
println!("平方: {:?}", squares);
// 链式转换
let result: Vec<String> = numbers
.iter()
.map(|x| x * 2)
.map(|x| format!("数字: {}", x))
.collect();
println!("转换结果: {:?}", result);
}
filter - 过滤元素
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 过滤偶数
let even_numbers: Vec<&i32> = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.collect();
println!("偶数: {:?}", even_numbers);
// 组合 filter 和 map
let even_squares: Vec<i32> = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.map(|x| x * x)
.collect();
println!("偶数的平方: {:?}", even_squares);
}
enumerate - 添加索引
fn main() {
let fruits = vec!["苹果", "香蕉", "橙子"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{}: {}", index, fruit);
}
// 找到特定元素的索引
let banana_index = fruits
.iter()
.enumerate()
.find(|(_, &fruit)| fruit == "香蕉")
.map(|(index, _)| index);
println!("香蕉的索引: {:?}", banana_index);
}
zip - 组合两个迭代器
fn main() {
let names = vec!["Alice", "Bob", "Charlie"];
let ages = vec![25, 30, 35];
// 组合两个迭代器
let people: Vec<(&str, &i32)> = names
.iter()
.zip(ages.iter())
.collect();
println!("人员信息: {:?}", people);
// 使用 zip 进行计算
let numbers1 = vec![1, 2, 3, 4];
let numbers2 = vec![10, 20, 30, 40];
let sums: Vec<i32> = numbers1
.iter()
.zip(numbers2.iter())
.map(|(a, b)| a + b)
.collect();
println!("对应相加: {:?}", sums);
}
take 和 skip
fn main() {
let numbers: Vec<i32> = (1..=10).collect();
// 取前 5 个元素
let first_five: Vec<i32> = numbers
.iter()
.take(5)
.cloned()
.collect();
println!("前五个: {:?}", first_five);
// 跳过前 3 个元素
let skip_three: Vec<i32> = numbers
.iter()
.skip(3)
.cloned()
.collect();
println!("跳过前三个: {:?}", skip_three);
// 组合使用
let middle: Vec<i32> = numbers
.iter()
.skip(2)
.take(5)
.cloned()
.collect();
println!("中间五个: {:?}", middle);
}
消费者适配器
消费者适配器会消费迭代器并产生最终结果。
collect - 收集到集合
use std::collections::{HashMap, HashSet};
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// 收集到 Vec
let doubled: Vec<i32> = numbers
.iter()
.map(|x| x * 2)
.collect();
// 收集到 HashSet
let unique_numbers: HashSet<i32> = vec![1, 2, 2, 3, 3, 4]
.into_iter()
.collect();
// 收集到 HashMap
let word_lengths: HashMap<&str, usize> = vec!["hello", "world", "rust"]
.iter()
.map(|&word| (word, word.len()))
.collect();
println!("加倍: {:?}", doubled);
println!("唯一数字: {:?}", unique_numbers);
println!("单词长度: {:?}", word_lengths);
}
reduce 和 fold
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// reduce - 将迭代器减少为单个值
let sum = numbers.iter().reduce(|acc, x| acc + x);
println!("reduce 求和: {:?}", sum);
// fold - 带初始值的折叠
let sum = numbers.iter().fold(0, |acc, x| acc + x);
println!("fold 求和: {}", sum);
// 计算乘积
let product = numbers.iter().fold(1, |acc, x| acc * x);
println!("乘积: {}", product);
// 字符串连接
let words = vec!["Hello", " ", "World", "!"];
let sentence = words.iter().fold(String::new(), |acc, &word| acc + word);
println!("句子: {}", sentence);
}
find 和 position
fn main() {
let numbers = vec![1, 3, 5, 8, 13, 21];
// find - 找到第一个满足条件的元素
let first_even = numbers.iter().find(|&&x| x % 2 == 0);
println!("第一个偶数: {:?}", first_even);
// position - 找到第一个满足条件的元素的位置
let even_position = numbers.iter().position(|&x| x % 2 == 0);
println!("第一个偶数的位置: {:?}", even_position);
// any - 检查是否有元素满足条件
let has_even = numbers.iter().any(|&x| x % 2 == 0);
println!("是否有偶数: {}", has_even);
// all - 检查是否所有元素都满足条件
let all_positive = numbers.iter().all(|&x| x > 0);
println!("是否都是正数: {}", all_positive);
}
惰性求值
迭代器是惰性的,只有在需要时才会计算:
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// 这些操作不会立即执行
let iter = numbers
.iter()
.map(|x| {
println!("处理: {}", x);
x * 2
})
.filter(|&&x| x > 4);
println!("迭代器已创建,但还没有处理任何元素");
// 只有在调用消费者时才会执行
let result: Vec<i32> = iter.collect();
println!("结果: {:?}", result);
}
性能优化
零成本抽象
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 函数式风格
let sum1: i32 = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.map(|x| x * x)
.sum();
// 命令式风格(编译器会将上面的代码优化成类似这样)
let mut sum2 = 0;
for &x in &numbers {
if x % 2 == 0 {
sum2 += x * x;
}
}
println!("函数式求和: {}", sum1);
println!("命令式求和: {}", sum2);
assert_eq!(sum1, sum2);
}
避免不必要的分配
fn main() {
let text = "hello world rust programming";
// 好:使用迭代器,避免中间分配
let word_count = text
.split_whitespace()
.filter(|word| word.len() > 4)
.count();
// 避免:创建中间向量
let words: Vec<&str> = text.split_whitespace().collect();
let long_words: Vec<&str> = words.into_iter().filter(|word| word.len() > 4).collect();
let count = long_words.len();
println!("长单词数量: {}", word_count);
println!("避免的方式计数: {}", count);
}
实际应用示例
数据处理管道
#[derive(Debug)]
struct Person {
name: String,
age: u32,
salary: u32,
}
fn main() {
let people = vec![
Person { name: "Alice".to_string(), age: 30, salary: 50000 },
Person { name: "Bob".to_string(), age: 25, salary: 45000 },
Person { name: "Charlie".to_string(), age: 35, salary: 60000 },
Person { name: "Diana".to_string(), age: 28, salary: 55000 },
];
// 数据处理管道
let high_earners: Vec<&Person> = people
.iter()
.filter(|person| person.salary > 50000)
.filter(|person| person.age < 35)
.collect();
println!("高收入年轻人: {:?}", high_earners);
// 计算平均工资
let average_salary: f64 = people
.iter()
.map(|person| person.salary as f64)
.sum::<f64>() / people.len() as f64;
println!("平均工资: {:.2}", average_salary);
}
文件处理
use std::fs::File;
use std::io::{BufRead, BufReader};
fn process_file(filename: &str) -> std::io::Result<()> {
let file = File::open(filename)?;
let reader = BufReader::new(file);
let word_count: usize = reader
.lines()
.map(|line| line.unwrap_or_default())
.flat_map(|line| line.split_whitespace().map(String::from).collect::<Vec<_>>())
.filter(|word| word.len() > 3)
.count();
println!("长单词数量: {}", word_count);
Ok(())
}
fn main() {
// 注意:这需要一个实际的文件
// process_file("example.txt").unwrap_or_else(|e| println!("错误: {}", e));
// 模拟文件内容
let content = "This is a sample text file with various words of different lengths";
let word_count: usize = content
.split_whitespace()
.filter(|word| word.len() > 3)
.count();
println!("模拟文件中的长单词数量: {}", word_count);
}
迭代器是 Rust 中非常强大的特性,掌握它们可以让你写出更加优雅和高效的代码。下一节我们将深入学习迭代器适配器的高级用法。