🦀 第13课:闭包与迭代器

闭包和迭代器是Rust函数式编程的核心。闭包是可以捕获环境的匿名函数,迭代器提供了惰性求值的元素序列。二者结合,让你写出简洁、高效、安全的链式数据处理代码。

进阶特性 第13/25课

学习目标:掌握闭包语法与捕获、Fn/FnMut/FnOnce特征、迭代器适配器与消费者、自定义迭代器

🔒 闭包基础

fn main() {
    // 基本语法
    let add = |a, b| a + b;
    println!("3 + 5 = {}", add(3, 5));
    
    // 类型推断:闭包通常不需要标注类型
    let multiply = |x: i32, y: i32| -> i32 { x * y };
    println!("4 * 6 = {}", multiply(4, 6));
    
    // 多行闭包
    let complex = |x: i32| {
        let doubled = x * 2;
        let squared = doubled * doubled;
        squared
    };
    println!("复杂计算: {}", complex(3));
    
    // 捕获环境变量
    let factor = 3;
    let scale = |x| x * factor;  // 捕获factor
    println!("缩放: {}", scale(10));  // 30
    
    let greeting = String::from("Hello");
    let say = || println!("{}", greeting);  // 不可变借用greeting
    say();
    // greeting.push_str("!");  // ❌ say已借用greeting
    
    // 捕获可变引用
    let mut count = 0;
    let mut increment = || {
        count += 1;
        count
    };
    println!("count = {}", increment());
    println!("count = {}", increment());
    println!("最终count = {}", count);
    
    // move闭包:获取所有权
    let name = String::from("Rust");
    let owned = move || println!("拥有: {}", name);
    // println!("{}", name);  // ❌ name已被move
    owned();
}
3 + 5 = 8 4 * 6 = 24 复杂计算: 36 缩放: 30 Hello count = 1 count = 2 最终count = 2 拥有: Rust

✅ 验证通过

🎯 Fn / FnMut / FnOnce

特征捕获方式可调用次数示例
FnOnce获取所有权一次消耗捕获变量
FnMut可变借用多次(需mut)修改捕获变量
Fn不可变借用多次只读捕获变量
// FnOnce —— 只能调用一次
fn apply_once(f: F) where F: FnOnce() {
    f();
    // f();  // ❌ 不能再调用
}

// FnMut —— 可多次调用,需要mut
fn apply_twice(mut f: F) where F: FnMut() {
    f();
    f();
}

// Fn —— 可多次调用,不可变
fn apply_many(f: F, n: usize) where F: Fn() {
    for _ in 0..n {
        f();
    }
}

fn main() {
    let mut x = 0;
    
    // FnOnce: 消耗捕获的变量
    let s = String::from("hello");
    let consume = move || {
        let _taken = s;  // 获取所有权
        println!("消耗了s");
    };
    apply_once(consume);
    
    // FnMut: 修改捕获的变量
    let mut counter = 0;
    let mut increment = || { counter += 1; println!("counter={}", counter); };
    apply_twice(increment);
    
    // Fn: 只读
    let msg = "你好";
    let greet = || println!("{}", msg);
    apply_many(greet, 3);
}
消耗了s counter=1 counter=2 你好 你好 你好

✅ 验证通过

🔄 迭代器

迭代器适配器(惰性转换)

fn main() {
    let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // map —— 转换每个元素
    let squares: Vec = v.iter().map(|x| x * x).collect();
    println!("平方: {:?}", squares);
    
    // filter —— 过滤
    let evens: Vec<&i32> = v.iter().filter(|x| *x % 2 == 0).collect();
    println!("偶数: {:?}", evens);
    
    // 链式调用!
    let result: Vec = v.iter()
        .filter(|x| *x % 2 == 0)     // 偶数
        .map(|x| x * 3)               // 乘3
        .take(3)                       // 取前3个
        .collect();
    println!("链式: {:?}", result);
    
    // enumerate —— 带索引
    for (i, v) in v.iter().enumerate().take(5) {
        println!("[{}] = {}", i, v);
    }
    
    // zip —— 合并两个迭代器
    let names = vec!["Alice", "Bob", "Charlie"];
    let scores = vec![95, 87, 92];
    let pairs: Vec<(&str, i32)> = names.iter().zip(scores.iter()).map(|(n, s)| (*n, *s)).collect();
    println!("配对: {:?}", pairs);
    
    // flat_map —— 展平
    let words = vec!["hello world", "rust lang"];
    let all_words: Vec<&str> = words.iter()
        .flat_map(|s| s.split_whitespace())
        .collect();
    println!("展平: {:?}", all_words);
    
    // inspect —— 查看中间值(调试用)
    let sum: i32 = v.iter()
        .inspect(|x| println!("  检查: {}", x))
        .take(3)
        .sum();
    println!("前3个和: {}", sum);
}
平方: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 偶数: [2, 4, 6, 8, 10] 链式: [6, 12, 18] [0] = 1 [1] = 2 [2] = 3 [3] = 4 [4] = 5 配对: [("Alice", 95), ("Bob", 87), ("Charlie", 92)] 展平: ["hello", "world", "rust", "lang"] 检查: 1 检查: 2 检查: 3 前3个和: 6

✅ 验证通过

消费者(触发计算)

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    
    // collect —— 收集为集合
    let v2: Vec = v.iter().cloned().collect();
    
    // sum / product
    println!("和: {}", v.iter().sum::());
    println!("积: {}", v.iter().product::());
    
    // min / max
    println!("最小: {:?}", v.iter().min());
    println!("最大: {:?}", v.iter().max());
    
    // find / position
    println!("找到>3: {:?}", v.iter().find(|&&x| x > 3));
    println!("位置>3: {:?}", v.iter().position(|&x| x > 3));
    
    // any / all
    println!("有偶数: {}", v.iter().any(|&x| x % 2 == 0));
    println!("全正数: {}", v.iter().all(|&x| x > 0));
    
    // fold / reduce
    let sum = v.iter().fold(0, |acc, &x| acc + x);
    println!("fold求和: {}", sum);
    
    let product = v.iter().cloned().reduce(|acc, x| acc * x);
    println!("reduce求积: {:?}", product);
    
    // for_each
    v.iter().for_each(|x| print!("{} ", x));
    println!();
    
    // count
    let even_count = v.iter().filter(|&&x| x % 2 == 0).count();
    println!("偶数个数: {}", even_count);
}
和: 15 积: 120 最小: Some(1) 最大: Some(5) 找到>3: Some(&4) 位置>3: Some(3) 有偶数: true 全正数: true fold求和: 15 reduce求积: Some(120) 1 2 3 4 5 偶数个数: 2

✅ 验证通过

自定义迭代器

struct Fibonacci {
    curr: u64,
    next: u64,
}

impl Fibonacci {
    fn new() -> Self {
        Fibonacci { curr: 0, next: 1 }
    }
}

impl Iterator for Fibonacci {
    type Item = u64;
    fn next(&mut self) -> Option {
        let current = self.curr;
        self.curr = self.next;
        self.next = current + self.next;
        Some(current)
    }
}

struct RangeStep {
    start: i32,
    end: i32,
    step: i32,
}

impl RangeStep {
    fn new(start: i32, end: i32, step: i32) -> Self {
        RangeStep { start, end, step }
    }
}

impl Iterator for RangeStep {
    type Item = i32;
    fn next(&mut self) -> Option {
        if self.start < self.end {
            let val = self.start;
            self.start += self.step;
            Some(val)
        } else {
            None
        }
    }
}

fn main() {
    // 斐波那契数列前10项
    let fib: Vec = Fibonacci::new().take(10).collect();
    println!("斐波那契: {:?}", fib);
    
    // 前10个偶数斐波那契数
    let even_fib: Vec = Fibonacci::new()
        .filter(|&x| x % 2 == 0)
        .take(5)
        .collect();
    println!("偶数斐波那契: {:?}", even_fib);
    
    // 自定义步进范围
    let stepped: Vec = RangeStep::new(0, 20, 3).collect();
    println!("步进3: {:?}", stepped);
}
斐波那契: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 偶数斐波那契: [0, 2, 8, 34, 144] 步进3: [0, 3, 6, 9, 12, 15, 18]

✅ 验证通过

🏗️ 综合实战:学生成绩分析

use std::collections::HashMap;

#[derive(Debug, Clone)]
struct Student {
    name: String,
    scores: Vec,
}

impl Student {
    fn new(name: &str, scores: Vec) -> Self {
        Student { name: name.to_string(), scores }
    }
    
    fn average(&self) -> f64 {
        if self.scores.is_empty() { return 0.0; }
        self.scores.iter().sum::() / self.scores.len() as f64
    }
    
    fn highest(&self) -> Option {
        self.scores.iter().cloned().fold(f64::NAN, f64::max).into()
    }
}

fn main() {
    let students = vec![
        Student::new("Alice", vec![95.0, 88.0, 92.0, 90.0]),
        Student::new("Bob", vec![78.0, 82.0, 75.0, 80.0]),
        Student::new("Charlie", vec![99.0, 95.0, 98.0, 97.0]),
        Student::new("Diana", vec![85.0, 90.0, 88.0, 92.0]),
        Student::new("Eve", vec![72.0, 68.0, 75.0, 70.0]),
    ];
    
    // 全班平均分
    let class_avg = students.iter()
        .map(|s| s.average())
        .sum::() / students.len() as f64;
    println!("📊 全班平均: {:.1}", class_avg);
    
    // 排名(按平均分降序)
    let mut ranked: Vec<_> = students.iter()
        .map(|s| (s.name.clone(), s.average()))
        .collect();
    ranked.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
    println!("\n🏆 排名:");
    for (i, (name, avg)) in ranked.iter().enumerate() {
        println!("  {}. {} ({:.1})", i + 1, name, avg);
    }
    
    // 优秀学生(平均>90)
    let excellent: Vec<_> = students.iter()
        .filter(|s| s.average() > 90.0)
        .map(|s| s.name.clone())
        .collect();
    println!("\n🌟 优秀学生: {:?}", excellent);
    
    // 各科统计
    println!("\n📈 各科统计:");
    let subject_count = students[0].scores.len();
    for i in 0..subject_count {
        let (avg, max, min) = students.iter()
            .fold((0.0, f64::MIN, f64::MAX), |(sum, mx, mn), s| {
                (sum + s.scores[i], mx.max(s.scores[i]), mn.min(s.scores[i]))
            });
        println!("  科目{}: 均分={:.1} 最高={:.0} 最低={:.0}", 
                 i + 1, avg / students.len() as f64, max, min);
    }
}
📊 全班平均: 84.4 🏆 排名: 1. Charlie (97.2) 2. Alice (91.2) 3. Diana (88.8) 4. Bob (78.8) 5. Eve (71.2) 🌟 优秀学生: ["Alice", "Charlie"] 📈 各科统计: 科目1: 均分=85.8 最高=99 最低=72 科目2: 均分=84.6 最高=95 最低=68 科目3: 均分=85.6 最高=98 最低=75 科目4: 均分=85.8 最高=97 最低=70

✅ 验证通过

📝 练习

练习1:闭包工厂

编写函数make_multiplier(factor: i32) -> impl Fn(i32) -> i32,返回一个乘法器闭包。

练习2:管道处理

用迭代器实现:读取字符串列表→过滤长度>3→转大写→去重→排序→收集。

练习3:素数迭代器

实现Primes迭代器,生成无限素数序列。使用take(20)测试。

🏆 本课成就

🔒 下一课解锁:并发编程 —— 线程与通道

🔧 迭代器性能与零成本抽象

fn main() {
    let data: Vec = (1..=1_000_000).collect();
    
    // 命令式循环
    let mut sum1 = 0i64;
    for &x in &data {
        if x % 2 == 0 { sum1 += x as i64 * x as i64; }
    }
    
    // 迭代器链(零成本抽象——编译后与上面相同)
    let sum2: i64 = data.iter()
        .filter(|&&x| x % 2 == 0)
        .map(|&x| (x as i64) * (x as i64))
        .sum();
    
    assert_eq!(sum1, sum2);
    println!("结果一致: {}", sum1);
    println!("迭代器是零成本抽象——编译后与手写循环性能相同");
    
    // 惰性求值
    let iter = (1..).filter(|x| x % 2 == 0).map(|x| x * x);
    let first_5: Vec = iter.take(5).collect();
    println!("前5个偶数平方: {:?}", first_5);
    
    // 无限迭代器 + take
    let primes: Vec = {
        let mut primes = vec![];
        let mut n = 2u64;
        while primes.len() < 10 {
            if !primes.iter().any(|&p| n % p == 0) {
                primes.push(n);
            }
            n += 1;
        }
        primes
    };
    println!("前10个素数: {:?}", primes);
}
结果一致: 166667166667000 迭代器是零成本抽象——编译后与手写循环性能相同 前5个偶数平方: [4, 16, 36, 64, 100] 前10个素数: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

✅ 验证通过