Skip to content

迭代器与闭包

闭包和迭代器是 Rust 函数式编程的核心。它们让你能够编写简洁、表达力强的代码。

闭包是可以捕获环境的匿名函数。

fn main() {
// 普通函数
fn add_one_fn(x: i32) -> i32 {
x + 1
}
// 闭包的几种写法
let add_one_v1 = |x: i32| -> i32 { x + 1 };
let add_one_v2 = |x: i32| { x + 1 };
let add_one_v3 = |x: i32| x + 1;
let add_one_v4 = |x| x + 1; // 类型可以推断
println!("{}", add_one_v1(5));
}

闭包可以捕获定义它的作用域中的变量:

fn main() {
let x = 4;
let equal_to_x = |z| z == x; // 捕获了 x
let y = 4;
assert!(equal_to_x(y));
}

闭包根据使用方式自动选择捕获方式:

fn main() {
let list = vec![1, 2, 3];
let only_borrows = || println!("{:?}", list);
println!("调用前: {:?}", list);
only_borrows();
println!("调用后: {:?}", list); // list 仍然可用
}
fn main() {
let mut list = vec![1, 2, 3];
let mut borrows_mutably = || list.push(7);
// println!("{:?}", list); // 错误!已经有可变借用
borrows_mutably();
println!("{:?}", list); // [1, 2, 3, 7]
}
fn main() {
let list = vec![1, 2, 3];
// move 强制获取所有权
let takes_ownership = move || println!("{:?}", list);
// println!("{:?}", list); // 错误!list 已被移动
takes_ownership();
}
fn apply<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32,
{
f(x)
}
fn main() {
let double = |x| x * 2;
let result = apply(double, 5);
println!("{}", result); // 10
}
Trait含义调用方式
FnOnce只能调用一次,获取所有权self
FnMut可以多次调用,可变借用&mut self
Fn可以多次调用,不可变借用&self

关系:Fn : FnMut : FnOnce(每个都是前一个的子 trait)

fn call_once<F: FnOnce()>(f: F) {
f();
// f(); // 错误!FnOnce 只能调用一次
}
fn call_many<F: Fn()>(f: F) {
f();
f();
f(); // OK,可以调用多次
}
fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
move |x| x + n
}
fn main() {
let add_5 = make_adder(5);
println!("{}", add_5(10)); // 15
}

迭代器是一种模式,允许依次处理序列中的元素。

fn main() {
let v = vec![1, 2, 3];
// 不可变引用迭代器
let iter = v.iter();
// 可变引用迭代器
let mut v = vec![1, 2, 3];
let iter_mut = v.iter_mut();
// 获取所有权的迭代器
let v = vec![1, 2, 3];
let into_iter = v.into_iter();
}
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 还有很多默认方法...
}
fn main() {
let v = vec![1, 2, 3];
let mut iter = v.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), None);
}
fn main() {
let v = vec![1, 2, 3];
for val in v.iter() {
println!("{}", val);
}
// 等价于
let v = vec![1, 2, 3];
for val in &v {
println!("{}", val);
}
}

适配器(adapter)消费一个迭代器,产生另一个迭代器。

转换每个元素:

fn main() {
let v = vec![1, 2, 3];
let v2: Vec<_> = v.iter().map(|x| x * 2).collect();
println!("{:?}", v2); // [2, 4, 6]
}

过滤元素:

fn main() {
let v = vec![1, 2, 3, 4, 5, 6];
let even: Vec<_> = v.iter().filter(|x| *x % 2 == 0).collect();
println!("{:?}", even); // [2, 4, 6]
}
fn main() {
let v = vec![1, 2, 3, 4, 5];
let first_three: Vec<_> = v.iter().take(3).collect();
println!("{:?}", first_three); // [1, 2, 3]
let skip_two: Vec<_> = v.iter().skip(2).collect();
println!("{:?}", skip_two); // [3, 4, 5]
}

带索引遍历:

fn main() {
let v = vec!['a', 'b', 'c'];
for (index, value) in v.iter().enumerate() {
println!("{}: {}", index, value);
}
}

合并两个迭代器:

fn main() {
let a = [1, 2, 3];
let b = [4, 5, 6];
let zipped: Vec<_> = a.iter().zip(b.iter()).collect();
println!("{:?}", zipped); // [(1, 4), (2, 5), (3, 6)]
}

展平嵌套结构:

fn main() {
let nested = vec![vec![1, 2], vec![3, 4], vec![5]];
let flat: Vec<_> = nested.into_iter().flatten().collect();
println!("{:?}", flat); // [1, 2, 3, 4, 5]
}

连接两个迭代器:

fn main() {
let a = [1, 2, 3];
let b = [4, 5, 6];
let chained: Vec<_> = a.iter().chain(b.iter()).collect();
println!("{:?}", chained); // [1, 2, 3, 4, 5, 6]
}

消费器(consumer)消费迭代器,产生最终结果。

收集为集合:

use std::collections::HashMap;
fn main() {
// 收集为 Vec
let v: Vec<_> = (1..=5).collect();
// 收集为 HashMap
let map: HashMap<_, _> = vec![("a", 1), ("b", 2)].into_iter().collect();
}
fn main() {
let sum: i32 = (1..=5).sum();
println!("sum: {}", sum); // 15
let product: i32 = (1..=5).product();
println!("product: {}", product); // 120
}

自定义累积操作:

fn main() {
let v = vec![1, 2, 3, 4, 5];
// 初始值 0,累积函数
let sum = v.iter().fold(0, |acc, x| acc + x);
println!("sum: {}", sum); // 15
// 字符串拼接
let words = vec!["hello", "world"];
let sentence = words.iter().fold(String::new(), |acc, word| {
if acc.is_empty() {
word.to_string()
} else {
format!("{} {}", acc, word)
}
});
println!("{}", sentence); // "hello world"
}
fn main() {
let v = vec![1, 2, 3, 4, 5];
// 找到第一个满足条件的元素
let found = v.iter().find(|&&x| x > 3);
println!("{:?}", found); // Some(4)
// 找到位置
let pos = v.iter().position(|&x| x > 3);
println!("{:?}", pos); // Some(3)
}
fn main() {
let v = vec![1, 2, 3, 4, 5];
let has_even = v.iter().any(|&x| x % 2 == 0);
println!("有偶数: {}", has_even); // true
let all_positive = v.iter().all(|&x| x > 0);
println!("全是正数: {}", all_positive); // true
}
fn main() {
let v = vec![3, 1, 4, 1, 5, 9, 2, 6];
println!("数量: {}", v.iter().count()); // 8
println!("最小: {:?}", v.iter().min()); // Some(1)
println!("最大: {:?}", v.iter().max()); // Some(9)
}

迭代器方法可以链式调用:

fn main() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result: Vec<_> = v
.iter()
.filter(|&&x| x % 2 == 0) // 过滤偶数
.map(|&x| x * x) // 平方
.take(3) // 取前 3 个
.collect();
println!("{:?}", result); // [4, 16, 36]
}
struct Counter {
count: u32,
max: u32,
}
impl Counter {
fn new(max: u32) -> Counter {
Counter { count: 0, max }
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
if self.count < self.max {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
fn main() {
let counter = Counter::new(5);
for num in counter {
println!("{}", num);
}
// 输出: 1, 2, 3, 4, 5
}

迭代器是零成本抽象,编译后与手写循环性能相同:

// 这两段代码编译后性能一样
let sum: i32 = (1..=100).sum();
let mut sum = 0;
for i in 1..=100 {
sum += i;
}

编写一个函数,接收闭包并应用到每个元素:

fn apply_to_all<F>(v: Vec<i32>, f: F) -> Vec<i32>
where
F: Fn(i32) -> i32,
{
// 你的代码
}
fn main() {
let v = vec![1, 2, 3, 4, 5];
let doubled = apply_to_all(v, |x| x * 2);
println!("{:?}", doubled); // [2, 4, 6, 8, 10]
}

使用迭代器:过滤偶数 → 平方 → 求和

fn main() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result: i32 = // 你的代码
println!("结果: {}", result); // 应该是 4+16+36+64+100 = 220
}

实现一个 Fibonacci 迭代器:

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<Self::Item> {
// 你的代码
}
}
fn main() {
let fib: Vec<_> = Fibonacci::new().take(10).collect();
println!("{:?}", fib); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
}

使用 fold 拼接字符串数组:

fn main() {
let words = vec!["Hello", "World", "Rust"];
let sentence = // 使用 fold 拼接,用空格分隔
println!("{}", sentence); // "Hello World Rust"
}

掌握了迭代器和闭包后,下一章我们将学习智能指针——Rust 中管理堆内存的重要工具。