Learn
Rust/16-closures

闭包

闭包(closure) 是可以捕获环境的匿名函数。它语法紧凑,是迭代器与并发里的高频工具。

1. 闭包语法

闭包语法
fn main() {
    let add_one = |x: i32| x + 1;        // 单表达式
    let sum = |a, b| {                   // 多语句用花括号
        a + b
    };
    println!("{} {}", add_one(5), sum(2, 3));
}
💡类型通常可省略

闭包参数与返回类型大多能被编译器推断,比 fn 更省标注。仅在你想限定类型时才写。

2. 捕获环境

闭包能从定义处「借用」周围变量:

捕获环境
fn main() {
    let factor = 3;
    let scale = |x| x * factor;     // 捕获 factor
    println!("{}", scale(10));      // 30
}

3. Fn / FnMut / FnOnce

闭包按如何捕获变量自动实现这三个 trait:

trait捕获方式示例
Fn不可变借用 &T只读
FnMut可变借用 &mut T修改捕获值
FnOnce取得所有权 T消耗捕获值(如 move 移走)
let mut count = 0;
let mut inc = || { count += 1; };   // 实现 FnMut
inc();
println!("{}", count);
⚠️move 闭包会拿走所有权

move |...| ... 强制把捕获的变量 move 进闭包。跨线程传闭包时经常需要 move,但它会让原变量失效。

4. 闭包作为函数参数

用泛型 + trait bound 接收闭包:

闭包作为参数
fn apply<F>(f: F)
where
    F: Fn(i32) -> i32,
{
    println!("{}", f(5));
}
 
fn main() {
    apply(|x| x * 2);
}

5. 返回闭包

闭包无固定大小,需用 impl Fn 或 Box<dyn Fn>:

fn make_adder(n: i32) -> impl Fn(i32) -> i32 {
    move |x| x + n
}
ℹ️返回闭包用 impl Fn

因闭包是匿名类型,直接写返回类型不可行。用 impl Fn(...)->... 让编译器推导具体类型最干净。

🎯练习

写一个 fn apply_to_vec(v: Vec<i32>, f: impl Fn(i32) -> i32) -> Vec<i32>,把 f 应用到每个元素(用迭代器)。用闭包 |x| x * x 与 |x| x + 1 各调一次。

小结

  • 闭包语法 |参数| 体,类型常可省略
  • 捕获方式决定实现 Fn/FnMut/FnOnce
  • move 闭包拿走所有权,常用于跨线程
  • 参数用泛型 + Fn bound;返回用 impl Fn
  • 下一章看迭代器 →