Rust 语法学习 - 函数式编程特性
Rust 结合了多种编程范式,包括函数式编程。这里介绍 Rust 中的函数式编程特性:闭包和迭代器。
9.1 闭包
闭包是可以捕获环境的匿名函数。
闭包语法
// 基本语法
let add_one = |x| x + 1;
// 带类型注解的闭包
let add_one = |x: i32| -> i32 { x + 1 };
// 多行闭包
let calculate = |x| {
let mut result = x;
result += 10;
result * 2
};捕获环境
闭包可以使用包含它们的环境中的变量:
let x = 4;
// 闭包捕获x
let equal_to_x = |z| z == x;
assert!(equal_to_x(4));捕获方式
闭包可以通过三种方式捕获值,对应三种 Fn trait:
// FnOnce: 获取所有权,只能调用一次
let consume = || drop(x);
// FnMut: 可变借用
let mut counter = 0;
let mut increment = || {
counter += 1;
println!("Counter: {}", counter);
};
// Fn: 不可变借用
let print_greeting = || println!("Hello, {}", x);闭包根据其主体中对捕获变量的使用方式,自动实现适当的 trait:
Fn: 不可变借用FnMut: 可变借用FnOnce: 获取所有权
move 关键字
使用 move 关键字强制闭包获取其环境中变量的所有权:
let x = vec![1, 2, 3];
// 强制获取所有权,常用于线程
let consume = move || {
println!("消费: {:?}", x);
// x的所有权已经被移动到闭包中
};
// println!("{:?}", x); // 错误: x已经被移动闭包和函数
闭包类似于函数,但有更灵活的语法和捕获环境的能力:
// 函数 - 不能捕获环境
fn add_one_fn(x: i32) -> i32 {
x + 1
}
// 闭包 - 可以捕获环境
let y = 1;
let add_y = |x| x + y;返回闭包
由于闭包类型是匿名的,所以在函数返回闭包时需要使用 impl Trait 语法:
fn create_counter() -> impl Fn() -> i32 {
let mut count = 0;
move || {
count += 1;
count
}
}性能考虑
Rust 的闭包实现几乎没有运行时开销,同时保持类型安全和内存安全。
9.2 迭代器
迭代器允许你对一系列元素执行相同操作,是惰性的(不会在创建时计算)。
基本用法
let v = vec![1, 2, 3];
// 创建迭代器
let iter = v.iter();
// 使用for循环
for val in iter {
println!("值: {}", val);
}Iterator trait
所有迭代器都实现了 Iterator trait:
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// 其他默认方法...
}手动使用 next 方法:
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);迭代器方法
创建迭代器
let v = vec![1, 2, 3];
let iter1 = v.iter(); // 生成不可变引用的迭代器
let iter2 = v.iter_mut(); // 生成可变引用的迭代器
let iter3 = v.into_iter(); // 获取所有权的迭代器
// 范围迭代器
let range = 1..5; // 产生1, 2, 3, 4
let inclusive = 1..=5; // 产生1, 2, 3, 4, 5消费适配器
调用 next 方法的方法,它们消耗迭代器:
let v = vec![1, 2, 3];
// sum: 对元素求和
let total: i32 = v.iter().sum();
// count: 计数
let count = v.iter().count();
// any: 检查是否有任何元素满足条件
let has_even = v.iter().any(|&x| x % 2 == 0);
// all: 检查是否所有元素都满足条件
let all_positive = v.iter().all(|&x| x > 0);
// fold: 折叠
let sum = v.iter().fold(0, |acc, &x| acc + x);
// max/min: 找最大/最小值
let max = v.iter().max();
let min = v.iter().min();
// nth: 获取第n个元素
let third = v.iter().nth(2);
// find: 查找第一个满足条件的元素
let even = v.iter().find(|&&x| x % 2 == 0);
// position: 查找满足条件的第一个元素的位置
let pos = v.iter().position(|&x| x == 2);
// collect: 收集到容器中
let v2: Vec<i32> = v.iter().map(|&x| x + 1).collect();迭代器适配器
产生其他迭代器的方法,允许构建复杂的迭代器链:
let v = vec![1, 2, 3];
// map: 转换每个元素
let plus_one: Vec<i32> = v.iter().map(|&x| x + 1).collect();
// filter: 过滤元素
let even: Vec<&i32> = v.iter().filter(|&&x| x % 2 == 0).collect();
// zip: 将两个迭代器组合成一个迭代器
let names = vec!["Alice", "Bob", "Charlie"];
let ages = vec![30, 25, 35];
let persons: Vec<(&str, i32)> = names.iter()
.zip(ages.iter())
.map(|(name, age)| (*name, *age))
.collect();
// enumerate: 添加索引
for (i, val) in v.iter().enumerate() {
println!("第{}个元素是{}", i, val);
}
// chain: 连接两个迭代器
let v1 = vec![1, 2];
let v2 = vec![3, 4];
let chained: Vec<i32> = v1.iter().chain(v2.iter()).map(|&x| x).collect();
// take: 取前n个元素
let first_two: Vec<&i32> = v.iter().take(2).collect();
// skip: 跳过前n个元素
let last: Vec<&i32> = v.iter().skip(2).collect();
// rev: 反转迭代器
let reversed: Vec<&i32> = v.iter().rev().collect();
// flat_map: 映射并扁平化
let words = vec!["hello", "world"];
let chars: Vec<char> = words.iter()
.flat_map(|word| word.chars())
.collect();
// cloned: 克隆引用的值
let cloned: Vec<i32> = v.iter().cloned().collect();实现 Iterator trait
自定义类型可以实现 Iterator trait:
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
}
}
}
// 使用
let mut counter = Counter::new(3);
assert_eq!(counter.next(), Some(1));
assert_eq!(counter.next(), Some(2));
assert_eq!(counter.next(), Some(3));
assert_eq!(counter.next(), None);
// 使用其他迭代器方法
let sum: u32 = Counter::new(5).sum();
assert_eq!(sum, 15); // 1 + 2 + 3 + 4 + 5性能考虑
迭代器在 Rust 中是零开销抽象,编译器会优化迭代器代码为等效的低级代码,没有性能损失。
9.3 函数式编程模式
组合模式 (Pipeline)
通过链式调用创建数据处理管道:
let v = vec![1, 2, 3, 4, 5];
let sum_of_even_squares: i32 = v.iter()
.filter(|&&x| x % 2 == 0) // 只保留偶数
.map(|&x| x * x) // 计算平方
.sum(); // 求和
assert_eq!(sum_of_even_squares, 20); // 2² + 4² = 4 + 16 = 20高阶函数
将函数作为参数或返回函数的函数:
// 接受函数作为参数
fn apply_twice<F>(f: F, x: i32) -> i32
where
F: Fn(i32) -> i32
{
f(f(x))
}
let add_one = |x| x + 1;
let result = apply_twice(add_one, 5);
assert_eq!(result, 7); // (5 + 1) + 1 = 7
// 返回函数
fn create_adder(n: i32) -> impl Fn(i32) -> i32 {
move |x| x + n
}
let add_five = create_adder(5);
assert_eq!(add_five(10), 15);组合子模式
使用函数组合子构建更复杂的行为:
use std::collections::HashMap;
// 假设我们有一个处理Result的函数
fn process_data(data: &str) -> Result<i32, String> {
// 处理逻辑...
Ok(42)
}
let data = vec!["data1", "invalid", "data3"];
// map_or_else: 处理成功与失败情况
let results: Vec<i32> = data.iter()
.map(|&d| process_data(d).map_or_else(
|_err| 0, // 错误时返回0
|value| value * 2 // 成功时将值乘以2
))
.collect();记忆化和惰性求值
use std::collections::HashMap;
// 记忆化斐波那契数列
struct Fibonacci {
cache: HashMap<u64, u64>,
}
impl Fibonacci {
fn new() -> Fibonacci {
let mut cache = HashMap::new();
cache.insert(0, 0);
cache.insert(1, 1);
Fibonacci { cache }
}
fn calculate(&mut self, n: u64) -> u64 {
if !self.cache.contains_key(&n) {
let value = self.calculate(n - 1) + self.calculate(n - 2);
self.cache.insert(n, value);
}
*self.cache.get(&n).unwrap()
}
}
// 使用
let mut fib = Fibonacci::new();
assert_eq!(fib.calculate(10), 55);惰性序列
// 创建一个简单的无限序列
struct Integers {
current: i32,
}
impl Integers {
fn new() -> Integers {
Integers { current: 0 }
}
}
impl Iterator for Integers {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
let result = self.current;
self.current += 1;
Some(result)
}
}
// 使用
let first_five: Vec<i32> = Integers::new().take(5).collect();
assert_eq!(first_five, vec![0, 1, 2, 3, 4]);