Rust闭包(能够捕获周围作用域变量的匿名函数,广泛应用于迭代、过滤和映射)闭包变量三种捕获方式:通过引用(不可变引用)、通过可变引用和通过值(取得所有权)

ops/2024/11/14 6:54:26/

文章目录

      • Rust 闭包详解
        • 闭包的定义与语法
          • 基本语法
        • 闭包的特性
          • - 环境捕获(三种捕获方式:通过引用、通过可变引用和通过值(取得所有权))
            • 示例代码
          • - 内存安全与生命周期
            • 示例代码1
          • 示例代码2:闭包所有权转移
          • 示例代码3:传递可变引用
        • Rust 闭包的实际应用
          • - 迭代器操作
            • 示例代码
        • 总结
      • 补充:闭包变量三种捕获方式:通过引用(不可变引用)、通过可变引用和通过值(取得所有权)代码对比示例
        • 1. 通过引用捕获(不可变引用)
        • 2. 通过可变引用捕获
        • 3. 通过值捕获(取得所有权)

Rust 闭包详解

Rust 语言的闭包是一种能够捕获周围作用域变量的匿名函数。闭包在 Rust 中具有强大的表达力和灵活性,广泛应用于迭代、过滤和映射等功能。本文将深入探讨 Rust 闭包的定义、语法、特性以及实际应用示例。

闭包的定义与语法

闭包是 Rust 中一个可以捕获其环境并可以访问其作用域中变量的匿名函数。闭包通常是简短的,并且被定义在期望函数作为参数的地方。

基本语法

在 Rust 中,闭包的基本语法如下所示:

rust">let closure_name = |parameter_list| -> return_type {// 闭包体
};

闭包的定义开始于一个竖线 |,后面跟着参数列表,参数列表的结尾也是一个竖线 |。可选的返回类型可以使用 -> 符号指定,闭包体由花括号 {} 包裹。

闭包的特性
- 环境捕获(三种捕获方式:通过引用、通过可变引用和通过值(取得所有权))

闭包可以通过三种方式捕获其环境中的变量:通过引用、通过可变引用和通过值(取得所有权)。Rust 的编译器会根据闭包体内所使用的变量的方式自动推断如何捕获这些变量。

示例代码
rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let x = 4;let equal_to_x = |z| z == x;let y = 4;assert!(equal_to_x(y));println!("y is equal to x.");
}

在这里插入图片描述

在上述示例中,闭包 equal_to_x 通过引用捕获变量 x,因为闭包内部只是将 x 与传入的参数 z 进行比较,不需要修改 x

- 内存安全与生命周期

Rust 的所有权和借用规则同样适用于闭包。这意味着闭包内的捕获变量必须保证在闭包被调用时是有效的。Rust 编译器会检查这一点,确保闭包的使用是安全的。

示例代码1
rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let mut num = 5;{let mut add_num = |x: i32| num += x;add_num(5);}assert_eq!(num, 10);println!("num is now 10.");
}

在这里插入图片描述

这里的 add_num 闭包通过可变引用捕获外部变量 num,并在闭包体内修改 num 的值。

示例代码2:闭包所有权转移
rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let s = String::from("Hello");let push_string = |mut s_: String| s_.push_str(", world");push_string(s);// assert_eq!(s, String::from("Hello, world")); // 报错// println!("s is now \"Hello, world\".");
}
示例代码3:传递可变引用
// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let mut s = String::from("Hello");let push_string = |s_: &mut String| s_.push_str(", world");push_string(&mut s);assert_eq!(s, String::from("Hello, world"));println!("s is now \"Hello, world\".");
}

在这里插入图片描述

Rust 闭包的实际应用
- 迭代器操作

Rust 中的迭代器广泛使用闭包,尤其是在 mapfilterfold 等方法中。

示例代码
rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let numbers = vec![1, 2, 3, 4, 5];let squared_numbers: Vec<i32> = numbers.iter().map(|&x| x * x).collect();println!("Squared numbers: {:?}", squared_numbers); // 输出: [1, 4, 9, 16, 25]let even_numbers: Vec<i32> = numbers.into_iter().filter(|x| x % 2 == 0).collect();println!("Even numbers: {:?}", even_numbers); // 输出: [2, 4]
}

在这里插入图片描述

这个示例展示了如何使用闭包在迭代器上执行映射和过滤操作,map 用于计算平方,filter 用于选择偶数。

总结

Rust 的闭包提供了一个强大且灵活的工具,能够在许多不同的情境下灵活处理数据。通过闭包,Rust 程序员可以编写出既安全又高效的代码。

补充:闭包变量三种捕获方式:通过引用(不可变引用)、通过可变引用和通过值(取得所有权)代码对比示例

当然可以。以下是三个独立的代码块,每个代码块展示了 Rust 闭包中一种特定的变量捕获方式:通过引用、通过可变引用、和通过值(取得所有权)。每个示例都会通过闭包的参数来展示具体的捕获操作。

1. 通过引用捕获(不可变引用)

这个示例演示了闭包如何通过不可变引用捕获外部环境中的变量。

rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let color = String::from("blue");// 通过不可变引用捕获 colorlet print_color = |color_ref: &String| println!("Color: {}", color_ref);print_color(&color);
}

在这里插入图片描述

这里,print_color 是一个接收一个 &String 类型参数的闭包,它通过不可变引用来访问外部定义的 color 变量。

2. 通过可变引用捕获

这个示例展示了闭包如何通过可变引用捕获并修改外部环境中的变量。

rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let mut count = 0;// 通过可变引用捕获 countlet increment_count = |count_ref: &mut i32| {*count_ref += 1;println!("Count: {}", *count_ref);// println!("Count: {}", count_ref); // 都可以,自动判断的};increment_count(&mut count);increment_count(&mut count);
}

在这里插入图片描述

在这个示例中,increment_count 是一个接收 &mut i32 类型参数的闭包,它通过可变引用来修改传入的 count 变量。

3. 通过值捕获(取得所有权)

这个示例演示了闭包如何通过值捕获(取得所有权)外部环境中的变量。

rust">// 测试代码
#![allow(dead_code)] // 忽略全局dead code,放在模块开头!// #[derive(Debug)]fn main() {let color = String::from("blue");// 通过值捕获 colorlet consume_color = |color_val: String| println!("Moved Color: {}", color_val);consume_color(color);// 注意:在这里调用 consume_color 后,color 不再有效// 下面的代码如果取消注释,将会引起编译错误,因为 color 的所有权已经移至闭包中// println!("Try to access color: {}", color);
}

在这里插入图片描述

在这个示例中,consume_color 是一个接收 String 类型参数的闭包,它通过值捕获来获取 color 的所有权。一旦闭包被调用,原始的 color 变量就不再可用了。


这些代码块展示了如何明确通过闭包参数直接传递外部变量,并通过不同的捕获机制来处理这些变量。这种方式需要闭包调用者明确知道闭包的捕获机制和参数类型。


http://www.ppmy.cn/ops/132539.html

相关文章

bert-base-uncased处理文档

1.安装必要的库 确保安装 transformers 和 torch 库&#xff1a; pip install transformers torch 2.加载本地 BERT 模型和分词器 由于已将模型和分词器下载到本地&#xff0c;可以指定文件路径加载。确保路径与本地文件结构一致。 from transformers import BertTokenizer…

【Python】轻松实现机器翻译:Transformers库使用教程

轻松实现机器翻译&#xff1a;Transformers库使用教程 近年来&#xff0c;机器翻译技术飞速发展&#xff0c;从传统的基于规则的翻译到统计机器翻译&#xff0c;再到如今流行的神经网络翻译模型&#xff0c;尤其是基于Transformer架构的模型&#xff0c;翻译效果已经有了质的飞…

EasyExcel 学习之 导出 “提示问题”

EasyExcel 学习之 导出 “提示问题” 现象分析解决&#xff08;伪代码&#xff09;前端 POST 实现后端实现 现象 EasyExcel 支持导出 xlsx、xls、csv 三种文件格式。在导出过程中可能发生各种异常&#xff0c;当发生异常时应该提示错误信息而非导出一个错误的文件。 分析 首…

Hive操作库、操作表及数据仓库的简单介绍

数据仓库和数据库 数据库和数仓区别 数据库与数据仓库的区别实际讲的是OLTP与OLAP的区别 操作型处理(数据库)&#xff0c;叫联机事务处理OLTP&#xff08;On-Line Transaction Processing&#xff09;&#xff0c;也可以称面向用户交易的处理系统&#xff0c;它是针对具体业务…

基于 Encoder-Decoder 架构的大语言模型

基于 Encoder-Decoder 架构的大语言模型 Encoder-Decoder 架构 为了弥补 Encoder-only 架构在文本生成任务上的短板&#xff0c;Encoder-Decoder 架构在其基础上引入了一个解码器&#xff08;Decoder&#xff09;&#xff0c;并采用交叉注意力机制来实现编码器与解码器之间的…

aws申请ssl证书的方法【该证书仅供aws】

这里先声明&#xff0c;过程是对的&#xff0c;最终没有达到目的。 原本想着申请ssl证书替代&#xff0c;结果发现aws证书只能给自己的服务器用 但是整套申请证书以及下载&#xff0c;以及使用aws控制台的过程可以参考借鉴。 起因&#xff1a; 腾讯云的ssl证书越来越没法用了…

SpringMVC总结 我的学习笔记

SpringMVC总结 我的学习笔记 一、SpringMVC简介1.MVC2.SpringMVC概述3. SpringMVC中的核心组件4.SpringMVC核心架构流程 二、SpringMVC框架实例具体实现使用注解实现 四、数据处理及跳转1.结果跳转方式2.处理器方法的参数与返回值处理提交数据数据显示到前端 五、RestFul风格1.…

ORACLE 删除archivelog日志

监控信息 df -h 查看磁盘空间 /oracle 500G 已用 450G&#xff0c;剩余 50G 具体分析 /oracle/oraarch 421G 占绝对大头&#xff0c;看文件信息 &#xff0c;从2023年以来一直没有做过日志删除 参考ORACLE 正确删除归档日志的方法_oracle 清理归档日志-CSDN博客 0. 切换…