闭包基础
> 理解闭包的概念和价值,掌握闭包的基本语法,学会使用闭包简化代码。
为什么需要闭包?
闭包语法
概念名称: 闭包是匿名函数,可以捕获环境变量。
语法结构:
┌──────────────────────────────────────┐
│ let 闭包名 = |参数| { 表达式 }; │
│ ↑ ↑ ↑ │
│ 名字 参数列表 闭包体 │
│ │
│ let add = |x| x + 1; │
│ let add = |x: i32| -> i32 { x + 1 };│
│ │
│ 捕获环境变量: │
│ let n = 10; │
│ let add_n = |x| x + n; // 捕获 n │
│ │
│ 捕获方式:|&x|, |&mut x|, move闭包 │
└──────────────────────────────────────┘最简示例
rust
▶ Runfn main() {
let add = |x| x + 1;
println!("{}", add(5)); // 6
}代码复用问题
rust
▶ Run// 问题:需要对不同数据执行相同操作
// 方案 1:为每种操作写函数
fn add_one(x: i32) -> i32 { x + 1 }
fn add_two(x: i32) -> i32 { x + 2 }
fn multiply_by_2(x: i32) -> i32 { x * 2 }
// 方案 2:使用闭包(简洁)
let add_one = |x| x + 1;
let add_two = |x| x + 2;
let multiply_by_2 = |x| x * 2;回调函数需求
rust
▶ Run// 问题:需要传递"行为"给函数
// 使用闭包作为回调
fn process_data(data: Vec<i32>, transform: fn(i32) -> i32) -> Vec<i32> {
data.into_iter().map(transform).collect()
}
fn main() {
let data = vec![1, 2, 3, 4, 5];
// 传递不同的"行为"
let doubled = process_data(data.clone(), |x| x * 2);
let squared = process_data(data.clone(), |x| x * x);
let negated = process_data(data, |x| -x);
println!("doubled: {:?}", doubled);
println!("squared: {:?}", squared);
println!("negated: {:?}", negated);
}闭包的核心优势
┌─────────────────────────────────────────────────────┐
│ 闭包的优势 │
├─────────────────────────────────────────────────────┤
│ │
│ 1. 简洁性 │
│ • 无需写完整的函数定义 │
│ • 类型推断减少冗余 │
│ • 内联定义,逻辑清晰 │
│ │
│ 2. 捕获环境 │
│ • 可以访问定义位置的变量 │
│ • 自动管理借用关系 │
│ • 实现"闭包"语义 │
│ │
│ 3. 函数式编程 │
│ • 作为参数传递(高阶函数) │
│ • 作为返回值 │
│ • 链式组合操作 │
│ │
│ 4. 延迟计算 │
│ • 定义时不执行,调用时才执行 │
│ • 惰性迭代器的基础 │
│ • 控制流抽象 │
│ │
└─────────────────────────────────────────────────────┘
---
## 小结
- 闭包是匿名函数,可以捕获环境变量
- `|参数| 表达式` 是最简洁的闭包语法
- 闭包提供简洁性、环境捕获、函数式编程、延迟计算四大优势
- 作为回调函数传递,实现高阶函数模式
- 类型推断让闭包更简洁,但类型一旦确定就不能改变
## 练习题
详见:[练习题](../../exercises/18-closures)