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]
}
相关推荐
视觉小萌新9 小时前
AI Class 3 · Chapter 1:变量、字符串、list/dict、if/for(python学习-小白版-有经验可跳过)
python·学习·list
Ramble_Naylor12 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
yyyang8813 小时前
蓝牙系统整体架构详解
学习·信息与通信
程序边界13 小时前
一台数据集成软件的拆解笔记(下):一致性、容错、跑批与迁移,KFS 真正难的地方在这
java·前端·笔记
Linux-lucky13 小时前
46-Linux学习之旅之LVS负载均衡与keepalived高可用
linux·运维·学习·ubuntu·负载均衡·lvs
金色光环15 小时前
【DSP学习】C2000_ADC中断_笔记
笔记·学习
Дерек的学习记录15 小时前
Unreal Engine 5:第三人称运动系统和人物动画
开发语言·学习·ue5
zhangrelay15 小时前
mrpt杂乱笔记-26-10-31
笔记·学习
Ramble_Naylor15 小时前
Rust深度解读:异步流(Async Streams)与生成器的处理艺术
开发语言·后端·rust
熊猫钓鱼>_>15 小时前
平行视界兼容模式与魔法变量配置避坑【鸿蒙心迹】
运维·服务器·开发语言·笔记·华为·harmonyos·openharmony