适配器与消费者
学习目标
- 区分适配器和消费者
- 掌握链式调用模式
- 理解惰性求值的性能优势
核心概念
适配器 vs 消费者
适配器(惰性):返回新迭代器,不触发计算
iter().map().filter().enumerate()
↓
消费者(急性):触发实际计算
collect(), sum(), count(), for_each()
链式调用
fn main() {
let text = "hello world\nfoo bar\nrust is great";
let capitalized: Vec<String> = text
.lines()
.map(|line| {
let mut chars = line.chars();
match chars.next() {
None => String::new(),
Some(c) => {
let upper: String = c.to_uppercase().collect();
upper + chars.as_str()
}
}
})
.collect();
println!("{:?}", capitalized);
}
flat_map
fn main() {
let sentences = vec!["hello world", "foo bar baz"];
let words: Vec<&str> = sentences
.iter()
.flat_map(|s| s.split_whitespace())
.collect();
let nested = vec![vec![1, 2], vec![3, 4], vec![5]];
let flat: Vec<i32> = nested.into_iter().flat_map(|v| v.into_iter()).collect();
}
scan(有状态的 map)
fn main() {
let v = vec![1, 2, 3, 4, 5];
let running_sum: Vec<i32> = v
.iter()
.scan(0, |state, &x| {
*state += x;
Some(*state)
})
.collect();
}
take_while / skip_while
fn main() {
let v = vec![1, 2, 3, 0, 4, 5];
let prefix: Vec<_> = v.iter().take_while(|&&x| x > 0).collect();
let after_zero: Vec<_> = v.iter().skip_while(|&&x| x > 0).collect();
}
inspect(调试用)
fn main() {
let v = vec![1, 2, 3, 4, 5];
let result: Vec<i32> = v
.iter()
.inspect(|x| print!("输入: {} ", x))
.map(|x| x * 2)
.inspect(|x| print!("→ 输出: {} ", x))
.filter(|x| x > &5)
.inspect(|x| println!("→ 保留: {}", x))
.copied()
.collect();
println!("最终: {:?}", result);
}
unzip
fn main() {
let pairs = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let (numbers, letters): (Vec<i32>, Vec<char>) = pairs.into_iter().unzip();
}
实践练习
练习 1:CSV 解析
fn parse_csv(input: &str) -> Vec<Vec<String>> {
input
.lines()
.map(|line| {
line.split(',')
.map(|field| field.trim().to_string())
.collect()
})
.collect()
}
fn main() {
let csv = "name,age,city\nAlice,30,NYC\nBob,25,LA";
let data = parse_csv(csv);
for row in &data {
println!("{:?}", row);
}
}
练习 2:分组统计
fn group_by_first_char(words: &[&str]) -> std::collections::HashMap<char, Vec<&str>> {
let mut groups = std::collections::HashMap::new();
for &word in words {
if let Some(first) = word.chars().next() {
groups.entry(first).or_insert_with(Vec::new).push(word);
}
}
groups
}
fn main() {
let words = ["apple", "avocado", "banana", "blueberry", "cherry"];
let groups = group_by_first_char(&words);
for (ch, words) in &groups {
println!("{}: {:?}", ch, words);
}
}
练习 3:窗口统计
fn moving_average(data: &[f64], window: usize) -> Vec<f64> {
data.windows(window)
.map(|w| w.iter().sum::<f64>() / window as f64)
.collect()
}
fn main() {
let temps = vec![20.0, 22.0, 21.0, 23.0, 25.0, 24.0, 26.0];
let avg = moving_average(&temps, 3);
println!("3日移动平均: {:?}", avg);
}
常见错误
1. 惰性迭代器不执行
let v = vec![1, 2, 3];
v.iter().map(|x| println!("{}", x));
v.iter().for_each(|x| println!("{}", x));
2. 过度 collect
let step1: Vec<_> = v.iter().map(|x| x * 2).collect();
let step2: Vec<_> = step1.iter().filter(|x| x > &&5).collect();
let result: Vec<_> = v.iter().map(|x| x * 2).filter(|x| x > &5).collect();
小结
| 分类 | 方法 | 说明 |
|---|
| 适配器 | map, filter, enumerate | 返回新迭代器 |
| 适配器 | take, skip, chain | 限制/组合 |
| 适配器 | flat_map, scan, inspect | 高级转换 |
| 消费者 | collect, sum, count | 触发计算 |
| 消费者 | any, all, find, fold | 查找/累积 |