Rust学习笔记_12——闭包

Rust学习笔记_09------模式匹配
Rust学习笔记_10------守卫
Rust学习笔记_11------函数


闭包

文章目录

    • 闭包
      • [1. 基本特性](#1. 基本特性)
      • [2. 语法](#2. 语法)
      • [3. 类型](#3. 类型)
      • [4. 变量捕获方式](#4. 变量捕获方式)
        • [4.1 不可变捕获(Immutable Capture)](#4.1 不可变捕获(Immutable Capture))
        • [4.2 可变捕获(Mutable Capture)](#4.2 可变捕获(Mutable Capture))
        • [4.3 移动捕获(Move Capture)](#4.3 移动捕获(Move Capture))
      • [5. 示例](#5. 示例)

在Rust编程语言中,闭包(closures)是一种匿名函数,它能够捕获并存储其所在作用域内的变量,以便在稍后的某个时间点调用。闭包在Rust中非常有用,尤其是在处理回调函数、迭代器的适配器以及并行计算等场景时。闭包提供了灵活且强大的函数式编程特性。

1. 基本特性

  1. 匿名性:闭包没有名称,这使得它们非常适合作为参数传递给其他函数。
  2. 捕获环境:闭包可以捕获其定义作用域内的变量,这些变量在闭包被调用时仍然可用。捕获可以是不可变的(默认),也可以是可变的。
  3. 类型推断:Rust的编译器能够推断闭包的类型,但在某些情况下,你可能需要显式地指定类型(例如,在泛型上下文中)。
  4. 简洁性:闭包提供了一种简洁的方式来定义小型函数,尤其是当这些函数只需要在局部作用域内使用时。

2. 语法

Rust中的闭包使用||符号来定义,其语法类似于函数定义,但不需要指定函数名。闭包的参数和返回类型通常可以通过类型推断来确定。

rust 复制代码
let closure = |param1, param2| {
    // 函数体
    param1 + param2
};

3. 类型

闭包在Rust中是匿名的,但它们仍然有类型。这些类型通常很复杂,因此Rust允许你通过类型别名或泛型参数来简化闭包的使用。在大多数情况下,你不需要显式地指定闭包的类型,因为Rust的编译器能够推断它。

4. 变量捕获方式

4.1 不可变捕获(Immutable Capture)

不可变捕获是闭包捕获变量的默认方式。当闭包以不可变方式捕获变量时,它只能读取该变量的值,而不能修改它。这种方式保证了闭包内部对变量的访问是安全的,因为闭包不会改变变量的状态。

rust 复制代码
fn main() {
    let x = 10;

    // 定义一个闭包,它以不可变方式捕获变量x
    let print_x = || {
        println!("x = {}", x);
    };

    print_x(); // 输出: x = 10

    // 注意:闭包内部不能修改x的值
    // 下面的代码会导致编译错误
    // let modify_x = || {
    //     x = 20; // 错误:不能给不可变捕获的变量赋值
    // };
}
4.2 可变捕获(Mutable Capture)

可变捕获允许闭包修改其捕获的变量的值。为了使用可变捕获,你需要在闭包的定义中使用mut关键字来标记捕获的变量。这样,闭包就可以读取和修改该变量的值了。

rust 复制代码
fn main() {
    let mut counter = 0;

    // 定义一个闭包,它以可变方式捕获变量counter
    let increment = || {
        counter += 1;
        println!("counter = {}", counter);
    };

    increment(); // 输出: counter = 1
    increment(); // 输出: counter = 2
}
4.3 移动捕获(Move Capture)

移动捕获发生在闭包需要获取其捕获变量的所有权时。当闭包以移动方式捕获变量时,原始变量将不再可用,因为闭包已经接管了该变量的所有权。移动捕获通常发生在闭包需要将其捕获的变量带到另一个作用域或线程中时。

rust 复制代码
fn main() {
    let vec = vec![1, 2, 3];

    // 定义一个闭包,它以移动方式捕获变量vec
    let print_vec = || {
        for &x in &vec {
            println!("{}", x);
        }
    };

    // 在移动捕获后,原始变量vec将不再可用
    // 下面的代码会导致编译错误,因为vec的所有权已经被闭包接管
    // println!("{:?}", vec); // 错误:vec已经移动

    print_vec(); // 输出: 1 2 3

    // 由于vec的所有权已经被闭包接管,我们不能再访问vec
    // 但我们可以在闭包内部访问它,因为闭包拥有它的所有权
}

5. 示例

rust 复制代码
fn main() {
    let x = 10;

    // 定义一个闭包,它捕获了变量x(不可变捕获)
    let add_x = |y| x + y;

    println!("add_x(5) = {}", add_x(5)); // 输出: add_x(5) = 15

    // 定义一个闭包,它以可变方式捕获外部变量(需要显式地标记为mut)
    let mut counter = 0;
    let increment = || {
        counter += 1;
        counter
    };

    println!("increment() = {}", increment()); // 输出: increment() = 1
    println!("increment() = {}", increment()); // 输出: increment() = 2

    // 闭包作为函数参数
    let numbers = vec![1, 2, 3, 4, 5];
    let doubled = numbers.iter().map(|&x| x * 2).collect::<Vec<_>>();
    println!("{:?}", doubled); // 输出: [2, 4, 6, 8, 10]
}
相关推荐
先生沉默先1 小时前
Nginx 反向代理学习:单端口统一访问多服务
学习·nginx·arcgis
wei_shuo1 小时前
zoxide 开源鸿蒙 PC 生态适配实战:Rust 交叉编译与 HNP 打包完整指南
rust·开源鸿蒙·zoxide
sheeta19983 小时前
LeetCode 每日一题笔记 日期:2025.11.24 题目:1018. 可被5整除的二进制前缀
笔记·算法·leetcode
LFly_ice3 小时前
学习React-24-路由传参
前端·学习·react.js
陈天伟教授4 小时前
基于学习的人工智能(3)机器学习基本框架
人工智能·学习·机器学习·知识图谱
毕设源码-钟学长4 小时前
【开题答辩全过程】以 高校课程学习评价系统设计与实现为例,包含答辩的问题和答案
学习
chinesegf4 小时前
图文并茂的笔记、便签是如何用py开发的
笔记·状态模式
fruge6 小时前
从第三方库中偷师:学习 Lodash 的函数封装技巧
学习
lingggggaaaa8 小时前
免杀对抗——C2远控篇&C&C++&DLL注入&过内存核晶&镂空新增&白加黑链&签名程序劫持
c语言·c++·学习·安全·网络安全·免杀对抗
陈天伟教授9 小时前
基于学习的人工智能(5)机器学习基本框架
人工智能·学习·机器学习