26·函数式编程进阶

适配器与消费者

适配器与消费者

学习目标

  1. 区分适配器和消费者
  2. 掌握链式调用模式
  3. 理解惰性求值的性能优势

核心概念

适配器 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...