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 小时前
lua注意事项
开发语言·笔记·lua
拾忆-eleven2 小时前
NLP学习路线图(十五):TF-IDF(词频-逆文档频率)
人工智能·学习·自然语言处理·nlp
viperrrrrrrrrr72 小时前
大数据学习(125)-hive数据分析
大数据·学习
lulinhao3 小时前
VLAN的作用和原理
网络·笔记·vlan
UestcXiye4 小时前
Rust 学习笔记:发布一个 crate 到 crates.io
rust
moxiaoran57534 小时前
uni-app学习笔记十八--uni-app static目录简介
笔记·学习·uni-app
航Hang*4 小时前
WEBSTORM前端 —— 第3章:移动 Web —— 第4节:移动适配-VM
前端·笔记·edge·less·css3·html5·webstorm
Studying 开龙wu5 小时前
机器学习有监督学习sklearn实战二:六种算法对鸢尾花(Iris)数据集进行分类和特征可视化
学习·算法·机器学习
HinsCoder5 小时前
【技能拾遗】——家庭宽带单线复用布线与配置(移动2025版)
运维·网络·笔记·智能路由器·iptv·移动·单线复用
Lester_11016 小时前
嵌入式学习笔记 - STM32 HAL库以及标准库内核以及外设头文件区别问题
笔记·stm32·单片机·学习