Xz's blog Xz's blog
首页
时间序列
多模态
合成生物学
其他方向
生活
工具相关
PyTorch
导航站

Xu Zhen

首页
时间序列
多模态
合成生物学
其他方向
生活
工具相关
PyTorch
导航站
  • Rust

    • Rust 工具链
    • Cargo
    • 变量
    • 函数和控制流
    • 所有权
    • 引用与借用
    • Slice切片
    • 属性 Attribute
    • 闭包
      • Fn、FnMut 和 FnOnce
        • 1. FnOnce:消费所有权(最多调用一次)
        • 2. FnMut:可变借用(可多次调用,可修改环境)
        • 3. Fn:不可变借用(可多次并发调用,只读环境)
        • 总结与层级关系
    • Trait—关联类型(Associated Types)
    • 关联类型与泛型
    • 多线程 mpsc::channel
    • Rust 调用 C++ 之静态链接
    • Rust 调用 C++ 之动态链接
    • Rust与C++之间传递数据
  • Rust-Windows 窗口自动化

  • Tauri

  • C++

  • Claude Code

  • Liunx相关

  • Windows相关

  • IDE

  • Conda

  • Docker

  • VMware虚拟机

  • Python常用代码片段

  • 工具相关
  • Rust
xuzhen
2025-08-16
目录

闭包

# Fn、FnMut 和 FnOnce

在 Rust 中,Fn、FnMut 和 FnOnce 是三个 trait(特性),它们用于描述闭包(Closure)如何捕获和使用其环境中的变量。 编译器会根据闭包内部的行为自动为其实现这三个 trait 中最合适的一个。

这三个 trait 的核心区别在于它们如何与捕获的变量交互,这直接决定了闭包可以被调用多少次。


# 1. FnOnce:消费所有权(最多调用一次)

  • 含义: Once(一次)意味着这类闭包最多只能被调用一次。
  • 捕获方式:它通过获取环境中变量的所有权(taking ownership)来捕获它们。一旦闭包被调用,它会消费掉(consume)这些变量,导致所有权被移出闭包,因此闭包本身也无法再次被调用。
  • self 类型:可以类比为接收 self 参数的方法,它会消耗掉实例本身。

使用场景: 当你需要在闭包内部转移捕获变量的所有权时,例如,将一个 String 移动到一个新的线程中。

示例:

fn main() {
    let s = String::from("hello");

    // `move` 关键字强制闭包获取 s 的所有权
    let consume_s = move || {
        // s 的所有权在这里被消耗
        println!("s is: {}", s);
        // std::mem::drop(s); // 显式地丢弃 s
    };

    consume_s();

    // 下面这行代码会编译失败,因为 s 的所有权已经被移动到闭包中,
    // 并且在调用 consume_s() 后被销毁。
    // println!("Cannot use s here: {}", s);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2. FnMut:可变借用(可多次调用,可修改环境)

  • 含义:Mut(mutable)意味着这类闭包可以修改其捕获的环境变量。
  • 捕获方式:它以可变借用 (&mut T) 的方式捕获环境变量。因为只是借用,所以闭包可以被多次调用。
  • self 类型:可以类比为接收 &mut self 参数的方法,允许修改实例的状态。

使用场景: 当你需要一个可以被多次调用,并且每次调用都会改变其状态的闭包时,比如一个计数器。

示例:

fn main() {
    let mut count = 0;

    // 这个闭包需要修改 count 的值,所以它是一个 FnMut
    let mut increment = || {
        count += 1;
        println!("Count is now: {}", count);
    };

    increment(); // 输出: Count is now: 1
    increment(); // 输出: Count is now: 2

    // 可以在闭包外部再次访问 count,因为它只是被可变借用了
    println!("Final count: {}", count); // 输出: Final count: 2
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3. Fn:不可变借用(可多次并发调用,只读环境)

  • 含义:这是限制最严格的闭包类型,它只能读取环境变量,不能修改它们。
  • 捕获方式:它以不可变借用 (&T) 的方式捕获环境变量。因为是不可变借用,所以它可以被多次调用,甚至可以安全地在多个线程之间并发调用。
  • self 类型:可以类比为接收 &self 参数的方法,只能读取实例的状态。

使用场景: 当你只需要读取环境中的数据,而不需要修改它时。这是最灵活的闭包类型。

示例:

fn main() {
    let message = String::from("hello");

    // 这个闭包只是读取 message,所以它是一个 Fn
    let print_message = || {
        println!("Message is: {}", message);
    };

    print_message();
    print_message();

    // 在闭包之后,message 仍然完全可用
    println!("Message after closure: {}", message);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 总结与层级关系

这三个 trait 之间存在一个层级关系:

Fn ⊂ FnMut ⊂ FnOnce

这意味着:

  • 所有实现了 Fn 的闭包,也自动实现了 FnMut 和 FnOnce。
  • 所有实现了 FnMut 的闭包,也自动实现了 FnOnce。

换句话说,如果你有一个需要 FnOnce 类型闭包的函数,你可以给它传递一个 Fn 或 FnMut 类型的闭包,因为它们都可以被“调用一次”。但反过来则不行,例如,你不能把一个 FnOnce 闭包传递给一个要求 Fn 的函数,因为它可能会被多次调用。

Trait 捕获方式 调用次数 修改环境 self 类比
Fn 不可变借用 (&T) 多次 (可并发) 否 (只读) &self
FnMut 可变借用 (&mut T) 多次 (不可并发) 是 &mut self
FnOnce 获取所有权 (T) 最多一次 是/否 self
#Rust
上次更新: 2025/08/19, 08:47:47

← 属性 Attribute Trait—关联类型(Associated Types)→

最近更新
01
Linux 通过Windows代理上网
09-18
02
vscode远程使用copilot和codex(内网环境)
09-18
03
跨机器克隆环境
09-18
更多文章>
Theme by Vdoing | Copyright © 2025-2025 Xu Zhen | 鲁ICP备2025169719号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式