高级闭包应用
本节将探讨闭包在实际开发中的高级应用场景,包括函数式编程模式、异步编程、设计模式等。
函数式编程模式
高阶函数
// 返回闭包的函数
fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
move |x| x * factor
}
// 接受多个闭包的函数
fn combine_operations<F, G>(f: F, g: G) -> impl Fn(i32) -> i32
where
F: Fn(i32) -> i32,
G: Fn(i32) -> i32,
{
move |x| g(f(x))
}
fn main() {
let double = make_multiplier(2);
let add_ten = |x| x + 10;
let combined = combine_operations(double, add_ten);
println!("(5 * 2) + 10 = {}", combined(5)); // 20
}
柯里化(Currying)
// 柯里化函数:将多参数函数转换为单参数函数链
fn curry_add(x: i32) -> impl Fn(i32) -> i32 {
move |y| x + y
}
fn curry_multiply(x: i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
move |y| move |z| x * y * z
}
fn main() {
let add_5 = curry_add(5);
println!("5 + 3 = {}", add_5(3));
let multiply_2_3 = curry_multiply(2)(3);
println!("2 * 3 * 4 = {}", multiply_2_3(4));
}
偏函数应用
fn partial_apply<A, B, C, F>(f: F, a: A) -> impl Fn(B) -> C
where
F: Fn(A, B) -> C,
A: Clone,
{
move |b| f(a.clone(), b)
}
fn divide(a: f64, b: f64) -> f64 {
a / b
}
fn main() {
let divide_by_2 = partial_apply(divide, 2.0);
println!("10 / 2 = {}", divide_by_2(10.0));
let half_of = partial_apply(|x, y| x / y, 1.0);
println!("1 / 4 = {}", half_of(4.0));
}
异步编程中的闭包
Future 和闭包
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
// 自定义 Future,使用闭包作为计算
struct LazyFuture<F, T>
where
F: FnOnce() -> T,
{
computation: Option<F>,
}
impl<F, T> LazyFuture<F, T>
where
F: FnOnce() -> T,
{
fn new(computation: F) -> Self {
LazyFuture {
computation: Some(computation),
}
}
}
impl<F, T> Future for LazyFuture<F, T>
where
F: FnOnce() -> T,
{
type Output = T;
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
if let Some(computation) = self.computation.take() {
Poll::Ready(computation())
} else {
Poll::Pending
}
}
}
// 使用示例(需要 tokio)
#[cfg(feature = "tokio")]
#[tokio::main]
async fn main() {
let future = LazyFuture::new(|| {
println!("执行异步计算...");
42
});
let result = future.await;
println!("结果: {}", result);
}
#[cfg(not(feature = "tokio"))]
fn main() {
println!("需要 tokio 特性来运行异步示例");
}
异步回调模式
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
type AsyncCallback = Box<dyn Fn(String) + Send + Sync>;
struct AsyncEventEmitter {
listeners: Arc<Mutex<HashMap<String, Vec<AsyncCallback>>>>,
}
impl AsyncEventEmitter {
fn new() -> Self {
AsyncEventEmitter {
listeners: Arc::new(Mutex::new(HashMap::new())),
}
}
fn on<F>(&self, event: &str, callback: F)
where
F: Fn(String) + Send + Sync + 'static,
{
let mut listeners = self.listeners.lock().unwrap();
listeners
.entry(event.to_string())
.or_insert_with(Vec::new)
.push(Box::new(callback));
}
fn emit(&self, event: &str, data: String) {
let listeners = self.listeners.lock().unwrap();
if let Some(callbacks) = listeners.get(event) {
for callback in callbacks {
callback(data.clone());
}
}
}
}
fn main() {
let emitter = AsyncEventEmitter::new();
emitter.on("user_login", |data| {
println!("用户登录: {}", data);
});
emitter.on("user_login", |data| {
println!("记录日志: 用户 {} 已登录", data);
});
emitter.emit("user_login", "alice".to_string());
}
设计模式中的闭包
策略模式
struct PaymentProcessor<F>
where
F: Fn(f64) -> Result<String, String>,
{
strategy: F,
}
impl<F> PaymentProcessor<F>
where
F: Fn(f64) -> Result<String, String>,
{
fn new(strategy: F) -> Self {
PaymentProcessor { strategy }
}
fn process_payment(&self, amount: f64) -> Result<String, String> {
(self.strategy)(amount)
}
}
fn main() {
// 信用卡支付策略
let credit_card_processor = PaymentProcessor::new(|amount| {
if amount > 0.0 && amount <= 10000.0 {
Ok(format!("信用卡支付 ${:.2} 成功", amount))
} else {
Err("信用卡支付金额无效".to_string())
}
});
// PayPal 支付策略
let paypal_processor = PaymentProcessor::new(|amount| {
if amount > 0.0 && amount <= 5000.0 {
Ok(format!("PayPal 支付 ${:.2} 成功", amount))
} else {
Err("PayPal 支付金额超限".to_string())
}
});
println!("{:?}", credit_card_processor.process_payment(100.0));
println!("{:?}", paypal_processor.process_payment(100.0));
}
观察者模式
use std::sync::{Arc, Mutex};
type Observer<T> = Box<dyn Fn(&T) + Send + Sync>;
struct Observable<T> {
observers: Arc<Mutex<Vec<Observer<T>>>>,
value: Arc<Mutex<T>>,
}
impl<T> Observable<T>
where
T: Clone + Send + Sync + 'static,
{
fn new(initial_value: T) -> Self {
Observable {
observers: Arc::new(Mutex::new(Vec::new())),
value: Arc::new(Mutex::new(initial_value)),
}
}
fn subscribe<F>(&self, observer: F)
where
F: Fn(&T) + Send + Sync + 'static,
{
let mut observers = self.observers.lock().unwrap();
observers.push(Box::new(observer));
}
fn set_value(&self, new_value: T) {
{
let mut value = self.value.lock().unwrap();
*value = new_value;
}
let value = self.value.lock().unwrap();
let observers = self.observers.lock().unwrap();
for observer in observers.iter() {
observer(&*value);
}
}
fn get_value(&self) -> T {
self.value.lock().unwrap().clone()
}
}
fn main() {
let counter = Observable::new(0);
// 添加观察者
counter.subscribe(|value| {
println!("观察者1: 计数器变为 {}", value);
});
counter.subscribe(|value| {
if *value % 2 == 0 {
println!("观察者2: 计数器是偶数 {}", value);
}
});
// 触发通知
counter.set_value(1);
counter.set_value(2);
counter.set_value(3);
}
建造者模式
struct HttpRequest {
url: String,
method: String,
headers: Vec<(String, String)>,
body: Option<String>,
}
struct HttpRequestBuilder {
url: Option<String>,
method: String,
headers: Vec<(String, String)>,
body: Option<String>,
}
impl HttpRequestBuilder {
fn new() -> Self {
HttpRequestBuilder {
url: None,
method: "GET".to_string(),
headers: Vec::new(),
body: None,
}
}
fn configure<F>(mut self, configurator: F) -> Self
where
F: FnOnce(&mut Self),
{
configurator(&mut self);
self
}
fn url(mut self, url: &str) -> Self {
self.url = Some(url.to_string());
self
}
fn method(mut self, method: &str) -> Self {
self.method = method.to_string();
self
}
fn header(mut self, key: &str, value: &str) -> Self {
self.headers.push((key.to_string(), value.to_string()));
self
}
fn body(mut self, body: &str) -> Self {
self.body = Some(body.to_string());
self
}
fn build(self) -> Result<HttpRequest, String> {
let url = self.url.ok_or("URL is required")?;
Ok(HttpRequest {
url,
method: self.method,
headers: self.headers,
body: self.body,
})
}
}
fn main() {
let request = HttpRequestBuilder::new()
.url("https://api.example.com/users")
.method("POST")
.configure(|builder| {
builder.header("Content-Type", "application/json");
builder.header("Authorization", "Bearer token123");
builder.body(r#"{"name": "Alice", "email": "alice@example.com"}"#);
})
.build()
.unwrap();
println!("请求: {} {}", request.method, request.url);
println!("头部: {:?}", request.headers);
println!("主体: {:?}", request.body);
}
内存管理和性能优化
避免不必要的分配
// 不好:每次都创建新的闭包
fn bad_approach() -> Vec<Box<dyn Fn(i32) -> i32>> {
(0..1000)
.map(|i| Box::new(move |x| x + i) as Box<dyn Fn(i32) -> i32>)
.collect()
}
// 好:使用泛型避免装箱
fn good_approach<F>(generator: F) -> impl Iterator<Item = impl Fn(i32) -> i32>
where
F: Fn(usize) -> impl Fn(i32) -> i32,
{
(0..1000).map(generator)
}
fn main() {
let closures = good_approach(|i| move |x| x + i as i32);
for (i, closure) in closures.enumerate().take(5) {
println!("closure[{}](10) = {}", i, closure(10));
}
}
闭包大小优化
use std::mem;
fn demonstrate_closure_sizes() {
// 小闭包:不捕获变量
let small_closure = || 42;
println!("小闭包大小: {} bytes", mem::size_of_val(&small_closure));
// 中等闭包:捕获一个 i32
let x = 42;
let medium_closure = move || x;
println!("中等闭包大小: {} bytes", mem::size_of_val(&medium_closure));
// 大闭包:捕获大量数据
let large_data = vec![0; 1000];
let large_closure = move || large_data.len();
println!("大闭包大小: {} bytes", mem::size_of_val(&large_closure));
}
fn main() {
demonstrate_closure_sizes();
}
错误处理和闭包
Result 和 Option 的闭包操作
fn main() {
let numbers = vec!["1", "2", "not_a_number", "4"];
// 使用闭包处理 Result
let parsed: Vec<i32> = numbers
.iter()
.filter_map(|s| s.parse().ok())
.collect();
println!("解析成功的数字: {:?}", parsed);
// 错误处理闭包
let results: Vec<Result<i32, _>> = numbers
.iter()
.map(|s| s.parse())
.collect();
for (i, result) in results.iter().enumerate() {
match result {
Ok(num) => println!("索引 {}: 成功解析 {}", i, num),
Err(e) => println!("索引 {}: 解析失败 - {}", i, e),
}
}
}
自定义错误处理
#[derive(Debug)]
enum ProcessingError {
InvalidInput(String),
ProcessingFailed(String),
}
fn process_with_fallback<F, G, T>(
input: &str,
processor: F,
fallback: G,
) -> Result<T, ProcessingError>
where
F: FnOnce(&str) -> Result<T, ProcessingError>,
G: FnOnce(&str) -> T,
{
processor(input).or_else(|_| Ok(fallback(input)))
}
fn main() {
let inputs = vec!["123", "abc", "456"];
for input in inputs {
let result = process_with_fallback(
input,
|s| {
s.parse::<i32>()
.map_err(|_| ProcessingError::InvalidInput(s.to_string()))
},
|_| 0, // 默认值
);
println!("处理 '{}': {:?}", input, result);
}
}
测试中的闭包
模拟和测试替身
struct Database<F>
where
F: Fn(&str) -> Option<String>,
{
query_fn: F,
}
impl<F> Database<F>
where
F: Fn(&str) -> Option<String>,
{
fn new(query_fn: F) -> Self {
Database { query_fn }
}
fn get_user(&self, id: &str) -> Option<String> {
(self.query_fn)(id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_database_with_mock() {
// 使用闭包创建模拟数据库
let mock_db = Database::new(|id| {
match id {
"1" => Some("Alice".to_string()),
"2" => Some("Bob".to_string()),
_ => None,
}
});
assert_eq!(mock_db.get_user("1"), Some("Alice".to_string()));
assert_eq!(mock_db.get_user("2"), Some("Bob".to_string()));
assert_eq!(mock_db.get_user("3"), None);
}
}
fn main() {
// 生产环境中的真实数据库
let real_db = Database::new(|_id| {
// 这里会连接真实数据库
Some("Real User".to_string())
});
println!("用户: {:?}", real_db.get_user("1"));
}
最佳实践总结
1. 选择合适的捕获方式
fn demonstrate_capture_best_practices() {
let data = vec![1, 2, 3, 4, 5];
// 好:只借用需要的部分
let len = data.len();
let check_length = move || len > 3;
// 避免:捕获整个向量
// let check_length = move || data.len() > 3;
println!("长度检查: {}", check_length());
println!("原始数据仍可用: {:?}", data);
}
2. 合理使用生命周期
fn create_processor<'a>(prefix: &'a str) -> impl Fn(&str) -> String + 'a {
move |suffix| format!("{}-{}", prefix, suffix)
}
fn main() {
let prefix = "user";
let processor = create_processor(prefix);
println!("{}", processor("123"));
println!("{}", processor("456"));
}
3. 避免过度复杂的闭包
// 避免:过于复杂的闭包
fn avoid_complex_closure() {
let complex = |x: i32| {
let mut result = x;
for i in 1..10 {
result = result * i + (i % 2);
if result > 1000 {
result = result / 2;
}
}
result
};
println!("复杂结果: {}", complex(5));
}
// 好:将复杂逻辑提取为函数
fn complex_calculation(x: i32) -> i32 {
let mut result = x;
for i in 1..10 {
result = result * i + (i % 2);
if result > 1000 {
result = result / 2;
}
}
result
}
fn use_simple_closure() {
let simple = |x| complex_calculation(x);
println!("简单结果: {}", simple(5));
}
闭包是 Rust 中非常强大的特性,掌握其高级应用可以让你编写更加优雅和高效的代码。