迭代器适配器(Iterator Adapters)
迭代器适配器是将一个迭代器转换为另一个迭代器的方法。它们是惰性的,只有在被消费者调用时才会执行。掌握各种适配器是高效使用 Rust 迭代器的关键。
转换适配器
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 strings: Vec<String> = numbers
.iter()
.map(|x| format!("数字: {}", x))
.collect();
println!("字符串: {:?}", strings);
// 复杂转换
#[derive(Debug)]
struct Point { x: i32, y: i32 }
let points: Vec<Point> = numbers
.iter()
.map(|&x| Point { x, y: x * 2 })
.collect();
println!("点: {:?}", points);
}
filter - 条件过滤
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 基本过滤
let even: Vec<&i32> = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.collect();
println!("偶数: {:?}", even);
// 复杂条件
let special: Vec<&i32> = numbers
.iter()
.filter(|&&x| x > 3 && x < 8)
.collect();
println!("3到8之间: {:?}", special);
// 字符串过滤
let words = vec!["hello", "world", "rust", "programming", "language"];
let long_words: Vec<&str> = words
.iter()
.filter(|word| word.len() > 5)
.cloned()
.collect();
println!("长单词: {:?}", long_words);
}
filter_map - 过滤并转换
fn main() {
let strings = vec!["1", "2", "not_a_number", "4", "5"];
// 解析数字,忽略无效的
let numbers: Vec<i32> = strings
.iter()
.filter_map(|s| s.parse().ok())
.collect();
println!("解析的数字: {:?}", numbers);
// 更复杂的例子
let mixed_data = vec!["apple:5", "banana:invalid", "orange:3", "grape:7"];
let fruit_counts: Vec<(&str, i32)> = mixed_data
.iter()
.filter_map(|item| {
let parts: Vec<&str> = item.split(':').collect();
if parts.len() == 2 {
if let Ok(count) = parts[1].parse::<i32>() {
Some((parts[0], count))
} else {
None
}
} else {
None
}
})
.collect();
println!("水果计数: {:?}", fruit_counts);
}
组合适配器
zip - 组合迭代器
fn main() {
let names = vec!["Alice", "Bob", "Charlie"];
let ages = vec![25, 30, 35];
let cities = vec!["New York", "London", "Tokyo"];
// 两个迭代器组合
let people: Vec<(&str, &i32)> = names
.iter()
.zip(ages.iter())
.collect();
println!("姓名和年龄: {:?}", people);
// 三个迭代器组合
let full_info: Vec<((&str, &i32), &str)> = names
.iter()
.zip(ages.iter())
.zip(cities.iter())
.collect();
println!("完整信息: {:?}", full_info);
// 更优雅的三元组合
let tuples: Vec<(&str, &i32, &str)> = names
.iter()
.zip(ages.iter())
.zip(cities.iter())
.map(|((name, age), city)| (*name, age, *city))
.collect();
println!("三元组: {:?}", tuples);
}
enumerate - 添加索引
fn main() {
let fruits = vec!["苹果", "香蕉", "橙子", "葡萄"];
// 基本枚举
for (index, fruit) in fruits.iter().enumerate() {
println!("{}: {}", index, fruit);
}
// 从指定索引开始
let indexed: Vec<(usize, &str)> = fruits
.iter()
.enumerate()
.map(|(i, &fruit)| (i + 1, fruit)) // 从1开始
.collect();
println!("从1开始的索引: {:?}", indexed);
// 找到特定元素的位置
let banana_position = fruits
.iter()
.enumerate()
.find(|(_, &fruit)| fruit == "香蕉")
.map(|(index, _)| index);
println!("香蕉的位置: {:?}", banana_position);
}
分割和分组适配器
chunk 相关方法
fn main() {
let numbers: Vec<i32> = (1..=12).collect();
// 使用 chunks 方法(需要先收集到切片)
let chunks: Vec<&[i32]> = numbers.chunks(3).collect();
println!("分块: {:?}", chunks);
// 使用迭代器实现分块效果
let chunked: Vec<Vec<i32>> = numbers
.iter()
.enumerate()
.fold(Vec::new(), |mut acc, (i, &x)| {
if i % 3 == 0 {
acc.push(Vec::new());
}
if let Some(last) = acc.last_mut() {
last.push(x);
}
acc
});
println!("迭代器分块: {:?}", chunked);
}
partition - 分区
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 分区为偶数和奇数
let (even, odd): (Vec<i32>, Vec<i32>) = numbers
.into_iter()
.partition(|&x| x % 2 == 0);
println!("偶数: {:?}", even);
println!("奇数: {:?}", odd);
// 字符串分区
let words = vec!["hello", "world", "rust", "programming", "language"];
let (short, long): (Vec<&str>, Vec<&str>) = words
.into_iter()
.partition(|word| word.len() <= 5);
println!("短单词: {:?}", short);
println!("长单词: {:?}", long);
}
窗口和步长适配器
windows 和 step_by
fn main() {
let numbers: Vec<i32> = (1..=10).collect();
// 滑动窗口(需要先转为切片)
let windows: Vec<&[i32]> = numbers.windows(3).collect();
println!("滑动窗口: {:?}", windows);
// 步长迭代
let every_second: Vec<i32> = (1..=10)
.step_by(2)
.collect();
println!("每隔一个: {:?}", every_second);
// 组合使用
let stepped_windows: Vec<&[i32]> = numbers
.windows(3)
.step_by(2)
.collect();
println!("步长窗口: {:?}", stepped_windows);
}
take 和 skip 系列
fn main() {
let numbers: Vec<i32> = (1..=20).collect();
// take - 取前 n 个
let first_five: Vec<i32> = numbers
.iter()
.take(5)
.cloned()
.collect();
println!("前五个: {:?}", first_five);
// skip - 跳过前 n 个
let skip_five: Vec<i32> = numbers
.iter()
.skip(5)
.cloned()
.collect();
println!("跳过前五个: {:?}", skip_five);
// take_while - 取满足条件的元素
let take_while_small: Vec<i32> = numbers
.iter()
.take_while(|&&x| x < 8)
.cloned()
.collect();
println!("取小于8的: {:?}", take_while_small);
// skip_while - 跳过满足条件的元素
let skip_while_small: Vec<i32> = numbers
.iter()
.skip_while(|&&x| x < 8)
.cloned()
.collect();
println!("跳过小于8的: {:?}", skip_while_small);
}
扁平化适配器
flat_map - 扁平映射
fn main() {
let words = vec!["hello", "world", "rust"];
// 将每个单词转换为字符向量,然后扁平化
let all_chars: Vec<char> = words
.iter()
.flat_map(|word| word.chars())
.collect();
println!("所有字符: {:?}", all_chars);
// 数字范围扁平化
let ranges = vec![1..4, 5..8, 10..13];
let all_numbers: Vec<i32> = ranges
.into_iter()
.flat_map(|range| range)
.collect();
println!("所有数字: {:?}", all_numbers);
// 复杂的扁平映射
let sentences = vec!["Hello world", "Rust is great", "Programming fun"];
let word_lengths: Vec<usize> = sentences
.iter()
.flat_map(|sentence| sentence.split_whitespace())
.map(|word| word.len())
.collect();
println!("单词长度: {:?}", word_lengths);
}
flatten - 扁平化
fn main() {
// 扁平化嵌套向量
let nested = vec![vec![1, 2], vec![3, 4, 5], vec![6]];
let flattened: Vec<i32> = nested
.into_iter()
.flatten()
.collect();
println!("扁平化: {:?}", flattened);
// 扁平化 Option
let options = vec![Some(1), None, Some(2), Some(3), None];
let values: Vec<i32> = options
.into_iter()
.flatten()
.collect();
println!("Option扁平化: {:?}", values);
// 扁平化 Result
let results: Vec<Result<i32, &str>> = vec![Ok(1), Err("error"), Ok(2), Ok(3)];
let success_values: Vec<i32> = results
.into_iter()
.flatten()
.collect();
println!("Result扁平化: {:?}", success_values);
}
检查和查找适配器
inspect - 调试和副作用
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let result: Vec<i32> = numbers
.iter()
.inspect(|x| println!("原始值: {}", x))
.map(|x| x * 2)
.inspect(|x| println!("加倍后: {}", x))
.filter(|&&x| x > 5)
.inspect(|x| println!("过滤后: {}", x))
.cloned()
.collect();
println!("最终结果: {:?}", result);
}
peekable - 预览下一个元素
use std::iter::Peekable;
fn main() {
let numbers = vec![1, 2, 2, 3, 3, 3, 4];
let mut iter = numbers.iter().peekable();
while let Some(¤t) = iter.next() {
let mut count = 1;
// 预览下一个元素
while let Some(&&next) = iter.peek() {
if next == current {
count += 1;
iter.next();
} else {
break;
}
}
println!("{} 出现了 {} 次", current, count);
}
}
自定义适配器
创建自定义适配器
// 自定义适配器:批处理
struct Batch<I> {
iter: I,
size: usize,
}
impl<I> Batch<I> {
fn new(iter: I, size: usize) -> Self {
Batch { iter, size }
}
}
impl<I> Iterator for Batch<I>
where
I: Iterator,
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
let mut batch = Vec::with_capacity(self.size);
for _ in 0..self.size {
if let Some(item) = self.iter.next() {
batch.push(item);
} else {
break;
}
}
if batch.is_empty() {
None
} else {
Some(batch)
}
}
}
// 为迭代器添加扩展方法
trait BatchExt: Iterator {
fn batch(self, size: usize) -> Batch<Self>
where
Self: Sized,
{
Batch::new(self, size)
}
}
impl<I: Iterator> BatchExt for I {}
fn main() {
let numbers: Vec<i32> = (1..=10).collect();
let batches: Vec<Vec<i32>> = numbers
.into_iter()
.batch(3)
.collect();
println!("批处理: {:?}", batches);
}
性能优化技巧
避免不必要的收集
fn main() {
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 不好:中间收集
let evens: Vec<i32> = numbers.iter().filter(|&&x| x % 2 == 0).cloned().collect();
let sum: i32 = evens.iter().sum();
// 好:直接链式操作
let sum_direct: i32 = numbers
.iter()
.filter(|&&x| x % 2 == 0)
.sum();
println!("中间收集求和: {}", sum);
println!("直接求和: {}", sum_direct);
}
使用 Iterator::fold 而不是 collect + reduce
fn main() {
let words = vec!["hello", "world", "rust", "programming"];
// 不够优化:先收集再处理
let lengths: Vec<usize> = words.iter().map(|word| word.len()).collect();
let total: usize = lengths.iter().sum();
// 更好:直接折叠
let total_direct: usize = words
.iter()
.map(|word| word.len())
.sum();
// 最优:使用 fold
let total_fold: usize = words
.iter()
.fold(0, |acc, word| acc + word.len());
println!("收集后求和: {}", total);
println!("直接求和: {}", total_direct);
println!("fold求和: {}", total_fold);
}
实际应用示例
数据分析管道
#[derive(Debug, Clone)]
struct Sale {
product: String,
amount: f64,
region: String,
month: u32,
}
fn main() {
let sales = vec![
Sale { product: "Laptop".to_string(), amount: 1200.0, region: "North".to_string(), month: 1 },
Sale { product: "Phone".to_string(), amount: 800.0, region: "South".to_string(), month: 1 },
Sale { product: "Laptop".to_string(), amount: 1200.0, region: "North".to_string(), month: 2 },
Sale { product: "Tablet".to_string(), amount: 600.0, region: "East".to_string(), month: 2 },
];
// 分析:按产品分组并计算总销售额
use std::collections::HashMap;
let product_totals: HashMap<String, f64> = sales
.iter()
.fold(HashMap::new(), |mut acc, sale| {
*acc.entry(sale.product.clone()).or_insert(0.0) += sale.amount;
acc
});
println!("产品销售总额: {:?}", product_totals);
// 找出最高销售额的产品
let top_product = product_totals
.iter()
.max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
.map(|(product, amount)| (product.clone(), *amount));
println!("最高销售额产品: {:?}", top_product);
}
文本处理
fn main() {
let text = "The quick brown fox jumps over the lazy dog. The dog was sleeping.";
// 单词频率统计
use std::collections::HashMap;
let word_count: HashMap<&str, usize> = text
.split_whitespace()
.map(|word| word.trim_matches(|c: char| !c.is_alphabetic()).to_lowercase())
.fold(HashMap::new(), |mut acc, word| {
*acc.entry(word.as_str()).or_insert(0) += 1;
acc
});
// 注意:这里有生命周期问题,实际使用中需要处理
// 简化版本:
let word_count_simple: HashMap<String, usize> = text
.split_whitespace()
.map(|word| word.trim_matches(|c: char| !c.is_alphabetic()).to_lowercase())
.fold(HashMap::new(), |mut acc, word| {
*acc.entry(word).or_insert(0) += 1;
acc
});
println!("单词频率: {:?}", word_count_simple);
// 找出最常见的单词
let most_common = word_count_simple
.iter()
.max_by_key(|(_, &count)| count)
.map(|(word, count)| (word.clone(), *count));
println!("最常见单词: {:?}", most_common);
}
迭代器适配器是 Rust 函数式编程的核心,掌握它们可以让你写出更加简洁和高效的代码。下一节我们将学习迭代器的高级应用和自定义实现。