闭包在 Rust 中提供了比标准函数更高级的抽象层次和更高的灵活性,特别适合处理那些需要访问或修改局部作用域变量的场景,而函数则更适合构建稳定、易于理解的公共API.
Rust 的闭包根据如何其捕获变量的方式被分类为 Fn, FnMut, 和 FnOnce 三类。
可以读取外部变量但不修改
#[test]
fn test_fn() {
// 定义一个变量,供闭包借用
let num = 5;
// 定义一个Fn类型的闭包,它不可变地借用num
let add_num = |x: i32| num + x; // 闭包体内的num是通过引用访问的,因此闭包为Fn类型
// 调用闭包两次,验证它可以多次借用不可变地访问num
println!("add_num with 10: {}", add_num(10)); // 输出 15
println!("add_num with 20: {}", add_num(20)); // 输出 25
}
注释: 闭包 add_num 可以多次调用,因为它只是借用 num 而不改变它,符合 Fn 类型闭包的特征
可以读取和修改外部变量
#[test]
fn test_fn_mut() {
// 定义一个可变变量,供闭包借用和修改
let mut counter = 0;
// 定义一个FnMut类型的闭包,它可以可变地借用counter
let mut increment_counter = || {
counter += 1; // 闭包体内部修改了counter,因此是FnMut类型
};
// 调用闭包两次,每次调用都会增加counter的值
increment_counter();
increment_counter();
println!("Counter after incrementing: {}", counter); // 输出 2
}
注释: 闭包 increment_counter 需要可变地借用 counter 并对其进行修改,因此它是 FnMut 类型。需要注意的是,同一时间只有一个 FnMut 类型的闭包可以修改同一个变量。
可以获取外部变量的所有权,这通常发生在需要移动所有权到另一个线程或进行消耗性操作时
#[test]
fn test_fn_once() {
// 定义一个变量,将被闭包移动
let message = "Hello, World!".to_string();
// 定义一个FnOnce类型的闭包,它通过move关键字获取message的所有权
let print_message = move || {
println!("{}", message); // 闭包体内部移动了message,因此是FnOnce类型
};
// 调用闭包一次,因为message的所有权已被转移
print_message(); // 输出 Hello, World!
// 注意:在此之后,不能再访问message,因为它已经被移动到了闭包内部
// println!("{}", message); // 这里会报错,因为message已经不存在于作用域中
}
注释: 通过使用 move 关键字,闭包 print_message 获取了 message 的所有权,这意味着 message 不能在闭包之外再次被使用,因此闭包是 FnOnce 类型。闭包只能被调用一次,因为一旦调用,被移动的所有权就完成了转移。
fn
关键字定义。函数名作为其标识符,可以在代码中被明确引用。