Rust - 迭代器和闭包
Rust:迭代器和闭包
Section titled “Rust:迭代器和闭包”迭代器(Iterators)和闭包(Closures)是 Rust 最强大的两个特性,深受函数式编程的影响。它们允许你编写简洁、富有表达力且高效的代码来处理数据序列。
迭代器:处理一系列项
Section titled “迭代器:处理一系列项”迭代器是一种模式,允许你对一系列项依次执行某些操作。在 Rust 中,迭代器是实现了标准库中 Iterator trait 的任何类型。这个 trait 的核心是 next 方法:
pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; // ... 许多其他具有默认实现的方法}next() 方法将序列中的每个项包装在 Some 中返回,当序列结束时,它返回 None。让我们看看如何从向量(vector)创建迭代器并手动使用它。
fn main() { let v1 = vec![1, 2, 3]; let mut v1_iter = v1.iter(); // 创建一个迭代器
// 手动使用 next() assert_eq!(v1_iter.next(), Some(&1)); assert_eq!(v1_iter.next(), Some(&2)); assert_eq!(v1_iter.next(), Some(&3)); assert_eq!(v1_iter.next(), None);}集合通常提供三种方法来创建迭代器,具体取决于它们如何处理数据的所有权:
| Method | Description | Item Type |
|---|---|---|
iter() | 创建一个迭代器,它不可变地借用每个元素。原始集合保持可用。 | &T |
into_iter() | 创建一个迭代器,它获取集合及其元素的所有权。集合被消耗。 | T |
iter_mut() | 创建一个迭代器,它可变地借用每个元素,允许就地修改。 | &mut T |
迭代器适配器的强大功能
Section titled “迭代器适配器的强大功能”迭代器的真正强大之处在于它们的适配器(adapter)方法。这些方法将一个迭代器转换为另一个。因为它们是惰性的(lazy),所以在你消费(consume)迭代器之前,它们不会产生性能开销。
fn main() { let v1: Vec<i32> = vec![1, 2, 3];
// .map() 接受一个闭包,并创建一个迭代器,该迭代器对每个元素调用该闭包。 // .collect() 是一个消费适配器,它将结果收集到集合中。 let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
println!("Original vector: {:?}", v1); // v1 仍然可用! println!("New vector: {:?}", v2);
assert_eq!(v2, vec![2, 3, 4]);}Original vector: [1, 2, 3]New vector: [2, 3, 4]闭包:捕获其环境的匿名函数
Section titled “闭包:捕获其环境的匿名函数”闭包是匿名函数,你可以将它们保存在变量中或作为参数传递给其他函数。与函数不同,闭包可以从它们定义的作用域中捕获值。
闭包的定义非常轻量,参数用竖线(|)括起来,后面是函数体。类型注解通常是可选的。
fn main() { // 一个接受一个参数的简单闭包 let add_one = |x: u32| -> u32 { x + 1 }; println!("3 + 1 = {}", add_one(3));
// 类型注解通常是可选的,Rust 可以推断它们。 let add_two = |x| x + 2; println!("10 + 2 = {}", add_two(10));}闭包可以从其周围作用域中“借用”或“获取”变量。Rust 根据变量在闭包内部的使用方式来推断如何执行此操作,选择不可变借用、可变借用或获取所有权。这由 Fn、FnMut 和 FnOnce trait 决定。
fn main() { let list = vec![1, 2, 3]; println!("Before defining closure: {:?}", list);
// 此闭包不可变地借用了 `list`(Fn trait)。 let prints_list = || println!("From closure: {:?}", list);
prints_list(); println!("After calling closure: {:?}", list); // `list` 仍然可用}结合迭代器和闭包:天作之合
Section titled “结合迭代器和闭包:天作之合”当你将迭代器和闭包结合起来时,真正的魔法就会发生。大多数迭代器适配器,如 map、filter 和 fold,都将闭包作为参数来定义其行为。
#[derive(Debug, PartialEq)]struct Shoe { size: u32, style: String,}
fn shoes_in_my_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> { shoes.into_iter() // 获取向量的所有权 .filter(|s| s.size == shoe_size) // 使用闭包按大小筛选 .collect() // 将结果收集到一个新向量中}
fn main() { let shoes = vec![ Shoe { size: 10, style: String::from("sneaker") }, Shoe { size: 13, style: String::from("sandal") }, Shoe { size: 10, style: String::from("boot") }, ];
let my_size_shoes = shoes_in_my_size(shoes, 10);
println!("Shoes in my size: {:?}", my_size_shoes);}Shoes in my size: [Shoe { size: 10, style: "sneaker" }, Shoe { size: 10, style: "boot" }]