loading...
闭包常以匿名函数的形式出现,但其本质是函数+引用其作用域中变量的环境组合而成的对象。其有三种主要的形式,一种是作为函数的参数传入或者被作为函数的返回值返回出去,并且一个闭包的匿名函数其能被赋予一个变量。其核心的特性是,能捕获其调用者上下文作用域中的变量。
🧠 关键点对比:闭包 vs 普通函数(Rust)
| 特性 | 闭包(Closure) | 函数(Function) |
|---|---|---|
| 语法 | 通常是匿名的:` | x |
| 是否能捕获上下文变量 | ✅ 可以 | ❌ 不可以,只能用参数传入 |
| 类型系统 | 实现 Fn, FnMut, FnOnce trait | 是一种固定函数指针类型 |
| 可作为对象存储 | ✅ 可以,能被装箱 (Box<dyn Fn()>) | ✅ 但没有捕获能力 |
| 性能 | 编译器优化强,几乎无性能损耗 | 通常更简单、更轻量 |
| 实际用途 | 异步、并发、状态封装 | 算法、常规业务逻辑 |
rust语言是一门静态语言,通常如果不去明确的写其类型,其rust编译器会手动的为rust去写类型。 比如,如下代码实际上等同于:
Fn:只读调用只能借用环境变量(不可变借用 &T)。
支持多次调用,不会改变环境变量。
最常用于函数式编程风格,比如 .map()、.filter() 等。
传入函数中做只读计算
可以多次调用、不会修改外部状态
FnMut:可变调用会可变借用捕获的变量(&mut T)。
闭包内部可以修改环境变量的状态。
支持多次调用,但要求外部变量可变。
你想在闭包中更新某些状态(如计数器)
传入 .for_each() 改变外部变量
FnOnce:只能调用一次闭包会获取变量所有权(T),用完就走。
一次性调用之后不能再次调用。
最灵活,也是所有闭包的最基础 Trait。
闭包中需要消费(move)捕获的变量
适合异步、线程、一次性执行等场景
所有 Fn 闭包 都是 FnMut 和 FnOnce
所有 FnMut 闭包 也是 FnOnce
你可以把 FnOnce 看成最宽松,Fn 是最严格
Rust 的闭包(closure)是匿名函数类型,且类型复杂(编译器自动推断,具体类型内部实现细节不同)。要返回闭包,需要注意:
Rust 不能直接写出闭包的具体类型,因为闭包是匿名且编译器生成的。
需要用 impl Fn* 或者 Box<dyn Fn*> 这种方式返回闭包。
impl Fn(匿名闭包类型)——最常用写法impl Fn(i32) -> i32 表示函数返回了一个实现了 Fn(i32) -> i32 的闭包类型(不暴露具体类型)。
move 关键字确保闭包捕获 x 的所有权,可以安全返回。
Box<dyn Fn>——动态分发(运行时)如果想返回多种不同闭包,或者闭包类型无法用 impl Fn 统一时,可以用:
Box<dyn Fn(i32) -> i32> 是一个 trait 对象,存放在堆上。
适合返回多种不同闭包,但会带来一点运行时开销。
闭包类型是匿名且独一无二的,类似:
它的具体类型是编译器生成的、无法手写。你只能:
用 impl Fn... 让编译器帮你隐藏具体类型
或用 Box<dyn Fn...> 动态封装
| 返回闭包方式 | 适用场景 | 优缺点 |
|---|---|---|
impl Fn | 返回单一闭包类型 | 零开销,简单,类型固定 |
Box<dyn Fn> | 返回不同闭包类型或多态时 | 灵活,但有堆分配和运行时开销 |
加载中...