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]
}
相关推荐
Alidme几秒前
cs106x-lecture14(Autumn 2017)-SPL实现
c++·学习·算法·codestepbystep·cs106x
小王努力学编程2 分钟前
【算法与数据结构】单调队列
数据结构·c++·学习·算法·leetcode
非 白10 分钟前
【Java】单例模式
java·笔记·单例模式
ZxsLoves14 分钟前
【【Systemverilog学习参考 简单的加法器验证-含覆盖率】】
学习·fpga开发
明阳mark37 分钟前
Ansible 学习笔记
笔记·学习·ansible
~kiss~1 小时前
python的thrift2pyi学习
windows·python·学习
Evaporator Core1 小时前
MATLAB学习之旅:数据建模与仿真应用
开发语言·学习·matlab
大米洗澡1 小时前
数字签名技术基础
python·学习·程序人生·面试·职场和发展
StickToForever2 小时前
第4章 信息系统架构(六)
经验分享·笔记·学习·职场和发展
JD技术委员会3 小时前
Rust 语法噪音这么多,是否适合复杂项目?
开发语言·人工智能·rust