rust学习-闭包

rust学习-闭包

  • [1. 闭包基础](#1. 闭包基础)
  • [2. 闭包语法详解](#2. 闭包语法详解)
  • [3. 闭包的三种类型](#3. 闭包的三种类型)
    • [3.1 Fn - 不可变借用](#3.1 Fn - 不可变借用)
    • [3.2 FnMut - 可变借用](#3.2 FnMut - 可变借用)
    • [3.3 FnOnce - 获取所有权](#3.3 FnOnce - 获取所有权)
  • [4. 闭包捕获环境的方式](#4. 闭包捕获环境的方式)
    • [4.1 不可变借用(默认)](#4.1 不可变借用(默认))
    • [4.2 可变借用](#4.2 可变借用)
    • [4.3 获取所有权(move)](#4.3 获取所有权(move))
    • [4.4 捕获多个变量的混合方式](#4.4 捕获多个变量的混合方式)
  • [5. 闭包作为函数参数](#5. 闭包作为函数参数)
    • [5.1 泛型参数](#5.1 泛型参数)
    • [5.2 trait 对象(动态分发)](#5.2 trait 对象(动态分发))
    • [5.3 接受不同类型的闭包](#5.3 接受不同类型的闭包)
  • [6. 闭包作为返回值](#6. 闭包作为返回值)
    • [6.1 返回闭包的挑战](#6.1 返回闭包的挑战)
    • [6.2 返回不同类型的闭包](#6.2 返回不同类型的闭包)
    • [6.3 闭包工厂模式](#6.3 闭包工厂模式)
  • [7. 闭包与迭代器](#7. 闭包与迭代器)
    • [7.1 常用迭代器方法](#7.1 常用迭代器方法)
    • [7.2 自定义迭代器适配器](#7.2 自定义迭代器适配器)
  • [8. 闭包与并发](#8. 闭包与并发)
    • [8.1 线程中的闭包](#8.1 线程中的闭包)
    • [8.2 通道与闭包](#8.2 通道与闭包)
    • [8.3 闭包与原子类型](#8.3 闭包与原子类型)
  • [9. 实际应用示例](#9. 实际应用示例)
    • [9.1 配置化算法](#9.1 配置化算法)
    • [9.2 事件处理系统](#9.2 事件处理系统)
    • [9.3 中间件系统](#9.3 中间件系统)
  • [10. 性能考虑](#10. 性能考虑)
    • [10.1 闭包 vs 函数指针](#10.1 闭包 vs 函数指针)
    • [10.2 内联优化](#10.2 内联优化)
    • [10.3 闭包大小与内存布局](#10.3 闭包大小与内存布局)

闭包是 Rust 中强大且灵活的特性,可以用于创建匿名函数并捕获环境中的变量。闭包在很多场景下都非常有用,比如迭代器、回调函数、并发编程等。

1. 闭包基础

什么是闭包?

闭包是可以捕获其所在环境的匿名函数。它们可以存储为变量、作为参数传递或从函数返回。

基本示例

rust 复制代码
fn main() {
    // 定义一个闭包
    let add_one = |x: i32| -> i32 { x + 1 };
    
    // 调用闭包
    let result = add_one(5);
    println!("5 + 1 = {}", result); // 输出: 6
    
    // 闭包可以捕获环境变量
    let y = 10;
    let add_y = |x| x + y;
    println!("5 + y = {}", add_y(5)); // 输出: 15
}

2. 闭包语法详解

完整语法 vs 简化语法

rust 复制代码
fn main() {
    // 1. 完整语法(显式类型注解)
    let closure1 = |x: i32, y: i32| -> i32 {
        let result = x + y;
        result * 2
    };
    
    // 2. 简化语法(类型推断)
    let closure2 = |x, y| x + y;
    
    // 3. 无参数闭包
    let get_answer = || 42;
    
    // 4. 单表达式闭包(省略花括号)
    let square = |x: i32| x * x;
    
    println!("closure1: {}", closure1(3, 4)); // 14
    println!("closure2: {}", closure2(3, 4)); // 7
    println!("get_answer: {}", get_answer()); // 42
    println!("square: {}", square(5)); // 25
}

闭包参数的特殊语法

rust 复制代码
fn main() {
    // 闭包可以指定引用类型作为参数
    let print_len = |s: &str| s.len();
    println!("长度: {}", print_len("hello")); // 5
    
    // 闭包可以有可变参数
    let mut counter = 0;
    let mut increment = || {
        counter += 1;
        println!("计数器: {}", counter);
    };
    
    increment(); // 计数器: 1
    increment(); // 计数器: 2
    
    // 闭包参数也可以有生命周期
    let get_first_char = |s: &str| -> Option<char> {
        s.chars().next()
    };
    println!("首字符: {:?}", get_first_char("Rust")); // Some('R')
}

3. 闭包的三种类型

Rust 闭包实现了三个 trait 中的一个或多个:Fn、FnMut、FnOnce。

3.1 Fn - 不可变借用

rust 复制代码
fn main() {
    let x = 10;
    
    // 这个闭包实现了 Fn,因为它以不可变方式借用 x
    let print_x = || println!("x = {}", x);
    
    print_x(); // x = 10
    print_x(); // x = 10(可以多次调用)
    
    // x 仍然可以访问
    println!("x 仍然是 {}", x); // x 仍然是 10
    
    // 传递 Fn 闭包
    fn call_twice<F: Fn()>(f: F) {
        f();
        f();
    }
    
    call_twice(print_x); // 打印两次 x = 10
}

3.2 FnMut - 可变借用

rust 复制代码
fn main() {
    let mut counter = 0;
    
    // 这个闭包实现了 FnMut,因为它以可变方式借用 counter
    let mut increment = || {
        counter += 1;
        println!("计数器: {}", counter);
    };
    
    increment(); // 计数器: 1
    increment(); // 计数器: 2
    
    // 注意:在可变借用活跃期间,不能访问 counter
    // println!("{}", counter); // 错误!
    
    // 但闭包调用结束后可以访问
    println!("最终值: {}", counter); // 最终值: 2
    
    // 传递 FnMut 闭包
    fn call_with_mut<F: FnMut()>(mut f: F) {
        f();
        f();
    }
    
    let mut another_counter = 0;
    call_with_mut(|| {
        another_counter += 1;
        println!("另一个计数器: {}", another_counter);
    });
}

3.3 FnOnce - 获取所有权

rust 复制代码
fn main() {
    let expensive_data = vec![1, 2, 3, 4, 5];
    
    // 这个闭包实现了 FnOnce,因为它获取了 expensive_data 的所有权
    let consume_data = || {
        println!("消耗数据: {:?}", expensive_data);
        // expensive_data 在这里被丢弃
    };
    
    consume_data(); // 消耗数据: [1, 2, 3, 4, 5]
    // consume_data(); // 错误!闭包只能调用一次,因为 expensive_data 已被移动
    
    // 使用 move 关键字的例子
    let data = String::from("重要数据");
    let take_ownership = move || {
        println!("获取所有权: {}", data);
    };
    
    take_ownership(); // 获取所有权: 重要数据
    // println!("{}", data); // 错误!data 的所有权已转移
}

类型之间的层级关系

rust 复制代码
fn main() {
    // Fn 是 FnMut 的子集,FnMut 是 FnOnce 的子集
    // 这意味着:
    // - 任何实现了 Fn 的闭包也实现了 FnMut 和 FnOnce
    // - 任何实现了 FnMut 的闭包也实现了 FnOnce
    
    // 示例:接受不同类型的闭包参数
    fn accept_fn<F: Fn()>(f: F) {
        f();
    }
    
    fn accept_fn_mut<F: FnMut()>(mut f: F) {
        f();
    }
    
    fn accept_fn_once<F: FnOnce()>(f: F) {
        f();
    }
    
    let immutable_closure = || println!("不可变闭包");
    let mut mutable_counter = 0;
    let mut mutable_closure = || {
        mutable_counter += 1;
        println!("可变闭包: {}", mutable_counter);
    };
    let expensive_string = String::from("数据");
    let once_closure = move || {
        println!("一次性闭包: {}", expensive_string);
    };
    
    // Fn 闭包可以传递给所有三个函数
    accept_fn(immutable_closure);
    accept_fn_mut(immutable_closure);
    accept_fn_once(immutable_closure);
    
    // FnMut 闭包可以传递给 FnMut 和 FnOnce
    accept_fn_mut(mutable_closure);
    accept_fn_once(mutable_closure);
    
    // FnOnce 闭包只能传递给 FnOnce
    accept_fn_once(once_closure);
}

4. 闭包捕获环境的方式

4.1 不可变借用(默认)

rust 复制代码
fn main() {
    let x = 5;
    let y = 10;
    
    // 闭包不可变借用 x 和 y
    let sum = || x + y;
    
    println!("和: {}", sum()); // 15
    println!("x: {}, y: {}", x, y); // x: 5, y: 10(仍然可访问)
    
    // 多个闭包可以同时不可变借用
    let product = || x * y;
    println!("积: {}", product()); // 50
}

4.2 可变借用

rust 复制代码
fn main() {
    let mut counter = 0;
    
    // 闭包可变借用 counter
    let mut increment = || {
        counter += 1;
        println!("计数: {}", counter);
    };
    
    increment(); // 计数: 1
    increment(); // 计数: 2
    
    // 在此期间不能有其他引用
    // println!("{}", counter); // 错误!
    
    // 闭包调用结束后可以访问
    println!("最终计数: {}", counter); // 最终计数: 2
}

4.3 获取所有权(move)

rust 复制代码
fn main() {
    let data = vec![1, 2, 3, 4, 5];
    
    // 使用 move 强制闭包获取 data 的所有权
    let closure = move || {
        println!("数据长度: {}", data.len());
        // data 在这里被丢弃
    };
    
    closure(); // 数据长度: 5
    // println!("{:?}", data); // 错误!data 的所有权已转移
    
    // move 在并发编程中特别有用
    let message = String::from("来自主线程的消息");
    
    std::thread::spawn(move || {
        println!("线程收到: {}", message);
    }).join().unwrap();
}

4.4 捕获多个变量的混合方式

rust 复制代码
fn main() {
    let x = 10;           // i32,实现了 Copy
    let mut y = 20;       // 可变 i32
    let data = String::from("数据"); // String,没有实现 Copy
    
    let complex_closure = || {
        // x: 不可变借用(因为只是读取)
        println!("x = {}", x);
        
        // y: 可变借用(因为要修改)
        y += x;
        println!("y 现在是 {}", y);
        
        // data: 移动(使用 move 关键字时)
        // 但这里我们只是读取,所以默认是不可变借用
        println!("data = {}", data);
        
        // 如果我们想获取 data 的所有权,需要明确使用 move
    };
    
    complex_closure();
    println!("外部: x = {}, y = {}", x, y); // x 和 y 仍然可用
    println!("外部: data = {}", data); // data 仍然可用
}

5. 闭包作为函数参数

5.1 泛型参数

rust 复制代码
// 使用泛型和 trait 约束
fn apply<F>(value: i32, f: F) -> i32
where
    F: Fn(i32) -> i32,
{
    f(value)
}

fn main() {
    let double = |x| x * 2;
    let square = |x| x * x;
    
    println!("apply(5, double) = {}", apply(5, double)); // 10
    println!("apply(5, square) = {}", apply(5, square)); // 25
    
    // 捕获环境的闭包也可以传递
    let add_y = |x| {
        let y = 10;
        x + y
    };
    println!("apply(5, add_y) = {}", apply(5, add_y)); // 15
}

5.2 trait 对象(动态分发)

rust 复制代码
// 使用 Box<dyn Trait> 进行动态分发
fn process_numbers(numbers: &[i32], processor: Box<dyn Fn(i32) -> i32>) -> Vec<i32> {
    numbers.iter().map(|&n| processor(n)).collect()
}

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // 传递不同的处理器
    let doubled = process_numbers(&numbers, Box::new(|x| x * 2));
    println!("翻倍: {:?}", doubled); // [2, 4, 6, 8, 10]
    
    let incremented = process_numbers(&numbers, Box::new(|x| x + 10));
    println!("加10: {:?}", incremented); // [11, 12, 13, 14, 15]
}

5.3 接受不同类型的闭包

rust 复制代码
// 接受 Fn、FnMut 或 FnOnce 闭包
fn execute_closure<F>(f: F)
where
    F: FnOnce(),
{
    f();
}

// 更灵活:可以接受返回值的闭包
fn transform<F, T, R>(value: T, f: F) -> R
where
    F: FnOnce(T) -> R,
{
    f(value)
}

fn main() {
    // Fn 闭包
    execute_closure(|| println!("你好!"));
    
    // FnMut 闭包
    let mut count = 0;
    execute_closure(|| {
        count += 1;
        println!("计数: {}", count);
    });
    
    // FnOnce 闭包
    let data = String::from("数据");
    execute_closure(move || {
        println!("消耗: {}", data);
    });
    
    // 带返回值的闭包
    let result = transform(5, |x| x * 3);
    println!("结果: {}", result); // 15
}

6. 闭包作为返回值

6.1 返回闭包的挑战

rust 复制代码
// 简单情况:返回没有捕获环境的闭包
fn create_adder() -> impl Fn(i32, i32) -> i32 {
    |x, y| x + y
}

// 复杂情况:返回捕获了环境的闭包
fn make_multiplier(factor: i32) -> impl Fn(i32) -> i32 {
    // 必须使用 move,因为 factor 需要移动到闭包中
    move |x| x * factor
}

fn main() {
    let adder = create_adder();
    println!("3 + 4 = {}", adder(3, 4)); // 7
    
    let double = make_multiplier(2);
    println!("5 * 2 = {}", double(5)); // 10
    
    let triple = make_multiplier(3);
    println!("5 * 3 = {}", triple(5)); // 15
}

6.2 返回不同类型的闭包

rust 复制代码
// 使用 Box<dyn Trait> 返回不同类型的闭包
enum Operation {
    Add,
    Subtract,
    Multiply,
}

fn get_operation(op: Operation) -> Box<dyn Fn(i32, i32) -> i32> {
    match op {
        Operation::Add => Box::new(|x, y| x + y),
        Operation::Subtract => Box::new(|x, y| x - y),
        Operation::Multiply => Box::new(|x, y| x * y),
    }
}

fn main() {
    let add = get_operation(Operation::Add);
    let subtract = get_operation(Operation::Subtract);
    let multiply = get_operation(Operation::Multiply);
    
    println!("10 + 5 = {}", add(10, 5));      // 15
    println!("10 - 5 = {}", subtract(10, 5)); // 5
    println!("10 * 5 = {}", multiply(10, 5)); // 50
}

6.3 闭包工厂模式

rust 复制代码
// 创建配置化的闭包
fn create_logger(level: &'static str) -> impl Fn(&str) {
    move |message| println!("[{}] {}", level, message)
}

// 创建有状态的闭包
fn create_counter() -> impl Fn() -> i32 {
    let mut count = 0;
    
    move || {
        count += 1;
        count
    }
}

fn main() {
    // 日志记录器工厂
    let info_log = create_logger("INFO");
    let error_log = create_logger("ERROR");
    
    info_log("应用启动");
    error_log("发生错误");
    
    // 计数器工厂
    let mut counter1 = create_counter();
    let mut counter2 = create_counter();
    
    println!("计数器1: {}", counter1()); // 1
    println!("计数器1: {}", counter1()); // 2
    println!("计数器2: {}", counter2()); // 1(独立的计数器)
}

7. 闭包与迭代器

7.1 常用迭代器方法

rust 复制代码
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // map: 转换每个元素
    let doubled: Vec<i32> = numbers.iter().map(|&x| x * 2).collect();
    println!("翻倍: {:?}", doubled); // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
    
    // filter: 过滤元素
    let evens: Vec<&i32> = numbers.iter().filter(|&&x| x % 2 == 0).collect();
    println!("偶数: {:?}", evens); // [2, 4, 6, 8, 10]
    
    // filter_map: 过滤和转换
    let maybe_strings = vec!["1", "two", "3", "four", "5"];
    let numbers: Vec<i32> = maybe_strings
        .iter()
        .filter_map(|s| s.parse().ok())
        .collect();
    println!("解析的数字: {:?}", numbers); // [1, 3, 5]
    
    // fold: 累积
    let sum = numbers.iter().fold(0, |acc, &x| acc + x);
    println!("总和: {}", sum); // 15
    
    // reduce: 类似 fold,但使用第一个元素作为初始值
    let product = numbers.iter().copied().reduce(|acc, x| acc * x);
    println!("乘积: {:?}", product); // Some(15)
    
    // any 和 all: 条件检查
    let has_even = numbers.iter().any(|&x| x % 2 == 0);
    let all_positive = numbers.iter().all(|&x| x > 0);
    println!("有偶数吗? {}", has_even); // true
    println!("都正数吗? {}", all_positive); // true
}

7.2 自定义迭代器适配器

rust 复制代码
struct WindowIterator<'a, T> {
    data: &'a [T],
    window_size: usize,
    index: usize,
}

impl<'a, T> Iterator for WindowIterator<'a, T> {
    type Item = &'a [T];
    
    fn next(&mut self) -> Option<Self::Item> {
        if self.index + self.window_size <= self.data.len() {
            let window = &self.data[self.index..self.index + self.window_size];
            self.index += 1;
            Some(window)
        } else {
            None
        }
    }
}

fn main() {
    let data = vec![1, 2, 3, 4, 5];
    let window_iter = WindowIterator {
        data: &data,
        window_size: 3,
        index: 0,
    };
    
    // 使用闭包处理窗口
    let window_sums: Vec<i32> = window_iter
        .map(|window| window.iter().sum())
        .collect();
    
    println!("窗口和: {:?}", window_sums); // [6, 9, 12]
}

8. 闭包与并发

8.1 线程中的闭包

rust 复制代码
use std::thread;
use std::time::Duration;

fn main() {
    // 基本线程闭包
    let handle = thread::spawn(|| {
        for i in 1..5 {
            println!("线程: 计数 {}", i);
            thread::sleep(Duration::from_millis(100));
        }
    });
    
    // 主线程工作
    for i in 1..3 {
        println!("主线程: 计数 {}", i);
        thread::sleep(Duration::from_millis(200));
    }
    
    handle.join().unwrap();
    
    // 捕获数据的线程
    let data = vec![1, 2, 3, 4, 5];
    
    let handle = thread::spawn(move || {
        println!("线程中的数据: {:?}", data);
        // 计算总和
        let sum: i32 = data.iter().sum();
        sum
    });
    
    let result = handle.join().unwrap();
    println!("线程计算结果: {}", result); // 15
}

8.2 通道与闭包

rust 复制代码
use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    
    // 生成工作线程
    for i in 0..5 {
        let tx_clone = tx.clone();
        
        thread::spawn(move || {
            // 模拟一些工作
            let result = i * i;
            
            // 发送结果
            tx_clone.send((i, result)).unwrap();
        });
    }
    
    // 丢弃原始的发送者,这样接收者知道不会有更多数据
    drop(tx);
    
    // 收集所有结果
    let results: Vec<(i32, i32)> = rx.iter().collect();
    println!("结果: {:?}", results);
}

8.3 闭包与原子类型

rust 复制代码
use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::Arc;
use std::thread;

fn main() {
    let counter = Arc::new(AtomicI32::new(0));
    let mut handles = vec![];
    
    // 创建10个线程,每个线程增加计数器1000次
    for _ in 0..10 {
        let counter_clone = Arc::clone(&counter);
        
        let handle = thread::spawn(move || {
            for _ in 0..1000 {
                counter_clone.fetch_add(1, Ordering::SeqCst);
            }
        });
        
        handles.push(handle);
    }
    
    // 等待所有线程完成
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("最终计数: {}", counter.load(Ordering::SeqCst)); // 10000
}

9. 实际应用示例

9.1 配置化算法

rust 复制代码
// 策略模式使用闭包
struct DataProcessor<F> {
    processor: F,
}

impl<F> DataProcessor<F>
where
    F: Fn(&[i32]) -> i32,
{
    fn new(processor: F) -> Self {
        DataProcessor { processor }
    }
    
    fn process(&self, data: &[i32]) -> i32 {
        (self.processor)(data)
    }
}

fn main() {
    // 不同的处理策略
    let sum_processor = DataProcessor::new(|data| data.iter().sum());
    let avg_processor = DataProcessor::new(|data| {
        if data.is_empty() {
            0
        } else {
            data.iter().sum::<i32>() / data.len() as i32
        }
    });
    
    let data = vec![1, 2, 3, 4, 5];
    
    println!("总和: {}", sum_processor.process(&data)); // 15
    println!("平均值: {}", avg_processor.process(&data)); // 3
}

9.2 事件处理系统

rust 复制代码
struct EventEmitter {
    listeners: Vec<Box<dyn Fn(&str)>>,
}

impl EventEmitter {
    fn new() -> Self {
        EventEmitter { listeners: vec![] }
    }
    
    fn add_listener<F>(&mut self, listener: F)
    where
        F: Fn(&str) + 'static,
    {
        self.listeners.push(Box::new(listener));
    }
    
    fn emit(&self, event: &str) {
        for listener in &self.listeners {
            listener(event);
        }
    }
}

fn main() {
    let mut emitter = EventEmitter::new();
    
    // 添加事件监听器
    emitter.add_listener(|event| {
        println!("监听器1: 收到事件 '{}'", event);
    });
    
    emitter.add_listener(|event| {
        println!("监听器2: 处理事件 '{}'", event);
    });
    
    // 触发事件
    emitter.emit("应用启动");
    emitter.emit("用户登录");
}

9.3 中间件系统

rust 复制代码
type Middleware = Box<dyn Fn(&mut Context) -> Result<(), String>>;

struct Context {
    request: String,
    response: String,
    data: Vec<String>,
}

fn create_middleware_chain() -> Vec<Middleware> {
    vec![
        Box::new(|ctx: &mut Context| {
            println!("中间件1: 处理请求 '{}'", ctx.request);
            ctx.data.push("来自中间件1的数据".to_string());
            Ok(())
        }),
        Box::new(|ctx: &mut Context| {
            println!("中间件2: 验证请求");
            if ctx.request.is_empty() {
                return Err("空请求".to_string());
            }
            ctx.data.push("来自中间件2的数据".to_string());
            Ok(())
        }),
        Box::new(|ctx: &mut Context| {
            println!("中间件3: 生成响应");
            ctx.response = format!("对 '{}' 的响应", ctx.request);
            ctx.data.push("来自中间件3的数据".to_string());
            Ok(())
        }),
    ]
}

fn main() {
    let middleware_chain = create_middleware_chain();
    
    let mut context = Context {
        request: "获取数据".to_string(),
        response: String::new(),
        data: vec![],
    };
    
    // 执行中间件链
    for middleware in &middleware_chain {
        if let Err(e) = middleware(&mut context) {
            println!("错误: {}", e);
            return;
        }
    }
    
    println!("响应: {}", context.response);
    println!("数据: {:?}", context.data);
}

10. 性能考虑

10.1 闭包 vs 函数指针

rust 复制代码
// 闭包(无捕获)可以转换为函数指针
fn benchmark<F>(iterations: usize, f: F) -> std::time::Duration
where
    F: Fn(),
{
    let start = std::time::Instant::now();
    for _ in 0..iterations {
        f();
    }
    start.elapsed()
}

fn main() {
    let iterations = 1_000_000;
    
    // 函数指针
    fn simple_function() {
        // 什么都不做
    }
    
    // 闭包(无捕获)
    let closure = || {};
    
    // 测量性能
    let func_time = benchmark(iterations, simple_function);
    let closure_time = benchmark(iterations, closure);
    
    println!("函数指针时间: {:?}", func_time);
    println!("闭包时间: {:?}", closure_time);
    // 两者性能通常非常接近
}

10.2 内联优化

rust 复制代码
// 闭包通常可以被内联优化
fn process_with_closure<F>(data: &[i32], f: F) -> Vec<i32>
where
    F: Fn(i32) -> i32,
{
    data.iter().map(|&x| f(x)).collect()
}

fn main() {
    let data = vec![1, 2, 3, 4, 5];
    
    // 这个闭包很可能被内联
    let result = process_with_closure(&data, |x| x * 2);
    println!("结果: {:?}", result);
    
    // 捕获环境的闭包可能不会被内联
    let factor = 3;
    let result2 = process_with_closure(&data, |x| x * factor);
    println!("结果2: {:?}", result2);
}

10.3 闭包大小与内存布局

rust 复制代码
use std::mem;

fn main() {
    // 无捕获的闭包大小
    let closure1 = || println!("无捕获");
    println!("无捕获闭包大小: {} 字节", mem::size_of_val(&closure1));
    
    // 捕获 i32 的闭包
    let x = 42;
    let closure2 = || println!("x = {}", x);
    println!("捕获 i32 的闭包大小: {} 字节", mem::size_of_val(&closure2));
    
    // 捕获 String 的闭包
    let s = String::from("hello");
    let closure3 = move || println!("s = {}", s);
    println!("捕获 String 的闭包大小: {} 字节", mem::size_of_val(&closure3));
    
    // 捕获多个变量的闭包
    let a = 1;
    let b = 2.0;
    let c = String::from("three");
    let closure4 = move || {
        println!("a = {}, b = {}, c = {}", a, b, c);
    };
    println!("捕获多个变量的闭包大小: {} 字节", mem::size_of_val(&closure4));
}

闭包的核心要点
1. 语法灵活 :|参数| 表达式 或 |参数| { 代码块 }
2. 类型推断 :编译器通常能推断出参数和返回类型
3. 三种 trait

  • Fn:不可变借用,可多次调用
  • FnMut:可变借用,可多次调用
  • FnOnce:获取所有权,只能调用一次

4. 捕获环境:可以捕获外部变量,通过不可变借用、可变借用或移动

最佳实践
1. 优先使用不可变借用 :除非需要修改捕获的变量
2. 适当使用 move :当闭包需要比捕获的变量活得久时
3. 考虑性能 :无捕获的闭包可以转换为函数指针,性能更好
4. 注意生命周期:返回闭包时要考虑生命周期问题

相关推荐
yangSnowy13 小时前
用python抓取网页数据的基础方法
开发语言·python
你喜欢喝可乐吗?14 小时前
FastAPI 入门笔记
笔记·fastapi
sheji341614 小时前
【开题答辩全过程】以 基于微信小程序的在线学习系统为例,包含答辩的问题和答案
学习·微信小程序·小程序
LucianaiB14 小时前
【保姆级教程】10分钟把手机变成AI Agent:自动刷课、回消息,学不会我“退网”!
后端
zfj32114 小时前
从源码层面解析一下ThreadLocal的工作原理
java·开发语言·threadlocal
墨笔之风14 小时前
java后端根据双数据源进行不同的接口查询
java·开发语言·mysql·postgres
Mr -老鬼14 小时前
功能需求对前后端技术选型的横向建议
开发语言·前端·后端·前端框架
IT=>小脑虎14 小时前
Go语言零基础小白学习知识点【基础版详解】
开发语言·后端·学习·golang
qq_4061761414 小时前
关于JavaScript中的filter方法
开发语言·前端·javascript·ajax·原型模式