Skip to content

Rust 闭包

闭包是 Rust 中一种可以捕获环境变量的匿名函数。本章节将介绍 Rust 中的闭包。

闭包定义

闭包的定义使用 || 语法:

rust
fn main() {
    // 简单闭包
    let add_one = |x| x + 1;
    println!("add_one(5) = {}", add_one(5));
    
    // 带类型注解的闭包
    let add_two = |x: i32| -> i32 { x + 2 };
    println!("add_two(5) = {}", add_two(5));
    
    // 多参数闭包
    let add = |x, y| x + y;
    println!("add(5, 3) = {}", add(5, 3));
    
    // 无参数闭包
    let say_hello = || println!("Hello!");
    say_hello();
}

闭包捕获环境变量

闭包可以捕获其定义环境中的变量:

rust
fn main() {
    let x = 5;
    
    // 捕获 x 作为不可变引用
    let add_x = |y| x + y;
    println!("add_x(3) = {}", add_x(3));
    
    // 捕获 x 作为可变引用
    let mut y = 10;
    let mut add_to_y = |z| y += z;
    add_to_y(5);
    println!("y = {}", y);
    
    // 捕获 x 的所有权
    let s = String::from("Hello");
    let take_s = move || println!("s = {}", s);
    take_s();
    // println!("s = {}", s); // 错误:s 的所有权已经被转移
}

闭包的类型推断

Rust 会为每个闭包创建一个唯一的类型,但闭包可以通过 Trait 来统一处理:

  • Fn:不可变捕获环境
  • FnMut:可变捕获环境
  • FnOnce:消费捕获的环境
rust
fn main() {
    // Fn 闭包
    let x = 5;
    let add_x = |y| x + y;
    
    // FnMut 闭包
    let mut y = 10;
    let mut add_to_y = |z| y += z;
    
    // FnOnce 闭包
    let s = String::from("Hello");
    let take_s = move || println!("s = {}", s);
}

闭包作为参数

可以将闭包作为函数参数:

rust
fn apply<F>(f: F) where F: FnOnce() {
    f();
}

fn apply_to_3<F>(f: F) -> i32 where F: Fn(i32) -> i32 {
    f(3)
}

fn main() {
    let greeting = "Hello";
    let say_hello = || println!("{}", greeting);
    apply(say_hello);
    
    let add_one = |x| x + 1;
    println!("apply_to_3(add_one) = {}", apply_to_3(add_one));
    
    // 直接传递闭包
    println!("apply_to_3(|x| x * 2) = {}", apply_to_3(|x| x * 2));
}

闭包作为返回值

可以返回闭包,但需要使用 Box 来包装:

rust
fn make_adder(x: i32) -> Box<dyn Fn(i32) -> i32> {
    Box::new(move |y| x + y)
}

fn main() {
    let add5 = make_adder(5);
    println!("add5(3) = {}", add5(3));
    
    let add10 = make_adder(10);
    println!("add10(3) = {}", add10(3));
}

闭包的应用

迭代器适配器

rust
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // map 方法使用闭包
    let doubled: Vec<_> = numbers.iter().map(|&x| x * 2).collect();
    println!("Doubled: {:?}", doubled);
    
    // filter 方法使用闭包
    let even: Vec<_> = numbers.iter().filter(|&&x| x % 2 == 0).collect();
    println!("Even: {:?}", even);
}

延迟计算

rust
fn main() {
    let expensive_calculation = || {
        println!("Performing expensive calculation...");
        // 模拟昂贵的计算
        std::thread::sleep(std::time::Duration::from_secs(1));
        42
    };
    
    println!("First call:");
    println!("Result: {}", expensive_calculation());
    
    println!("Second call:");
    println!("Result: {}", expensive_calculation());
}

回调函数

rust
fn perform_operation<F>(callback: F) where F: FnOnce(i32) {
    let result = 42;
    callback(result);
}

fn main() {
    perform_operation(|result| {
        println!("Operation result: {}", result);
    });
}

总结

  • 闭包:可以捕获环境变量的匿名函数
  • 语法:使用 || 定义
  • 捕获方式:不可变引用、可变引用、所有权
  • TraitFnFnMutFnOnce
  • 应用:迭代器适配器、延迟计算、回调函数

闭包是 Rust 中非常强大的特性,它允许我们编写更灵活、更简洁的代码。通过本章节的学习,你应该已经掌握了 Rust 中闭包的使用方法。