跳到主要内容

迭代器适配器(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(&current) = 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 函数式编程的核心,掌握它们可以让你写出更加简洁和高效的代码。下一节我们将学习迭代器的高级应用和自定义实现。