适配器与消费者
学习目标
- 区分适配器和消费者
- 掌握链式调用模式
- 理解惰性求值的性能优势
核心概念
适配器 vs 消费者
适配器(惰性):返回新迭代器,不触发计算
iter().map().filter().enumerate()
↓
消费者(急性):触发实际计算
collect(), sum(), count(), for_each()
链式调用
fn main() {
let text = "hello world\nfoo bar\nrust is great";
// 链式处理:每行首字母大写,收集为 Vec
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"];
// flat_map: map 然后 flatten
let words: Vec<&str> = sentences
.iter()
.flat_map(|s| s.split_whitespace())
.collect();
// ["hello", "world", "foo", "bar", "baz"]
// 嵌套展平
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();
// [1, 2, 3, 4, 5]
}
scan(有状态的 map)
fn main() {
let v = vec![1, 2, 3, 4, 5];
// scan: 带状态的映射
let running_sum: Vec<i32> = v
.iter()
.scan(0, |state, &x| {
*state += x;
Some(*state)
})
.collect();
// [1, 3, 6, 10, 15]
}
take_while / skip_while
fn main() {
let v = vec![1, 2, 3, 0, 4, 5];
// take_while: 取满足条件的前缀
let prefix: Vec<_> = v.iter().take_while(|&&x| x > 0).collect();
// [1, 2, 3]
// skip_while: 跳过满足条件的前缀
let after_zero: Vec<_> = v.iter().skip_while(|&&x| x > 0).collect();
// [0, 4, 5]
}
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();
// numbers: [1, 2, 3], letters: ['a', 'b', 'c']
}
实践练习
练习 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
// ⚠️ 中间 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 | 查找/累积 |
练习编辑器
rust
Loading...