Rust语言入门教程(十四) - 闭包Closure

2023-11-30 10:20

本文主要是介绍Rust语言入门教程(十四) - 闭包Closure,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是闭包

闭包在 Rust 中是非常强大的功能,允许你编写更灵活和表达性的代码。闭包的语法和功能在某些方面类似于其他语言(如 JavaScript 或 Python)中的匿名函数或 lambda 表达式。

在Rust中,当我们想要生成一个新的线程,或者是想在迭代中进行一些函数式编程对迭代变量进行处理时,通常就会用到闭包, 当然,在标准库中一些其他的常见的地方,也会涉及到闭包的使用。

闭包本质上是一个匿名函数,它可以从其所在的作用域中借用或捕获到一些变量或数据。

语法规范

|x, y| { x+y }

上面的代码展示了一个闭包的基本语法格式:

  • 在两个|之间是闭包的参数列表,参数之间用,分隔;
  • 参数不需要标注数据类型;
  • 竖线后面是一个匿名函数的代码块,可以用于代码调用;

其中,参数的类型和和匿名函数的返回值都是由编译器通过代码的上下文自动推断得出。让我们来看一个实际的例子:

let add = |x, y| { x + y };
add(1, 2); // return 3

上面的代码中,我们将闭包分配给了一个变量add, 然后通过传入参数1, 2调用这个闭包,这两个变量将被传入匿名函数执行,并返回3

捕获变量

闭包的参数列表可以为空,因此上面的例子可以是这样:

|| { x + y }

当然,匿名函数也可以为空,比如这样:

|| {}

但是显然这样做没什么意义,也没人会干这么无聊的事情。那么为什么参数列表可以为空呢,那匿名函数中的变量从何而来呢? 这就到了有意思的地方了, 闭包可以借用它被定义的作用域中的值的引用。

let s = "abc".to_string();
let f = || {println!("{}", s);
};f() // 输出 “abc”

在上面的代码中,我们创建了一个字符串变量s, 然后创建了一个闭包并分配给变量f, 其中的匿名函数借用了该作用域中变量s的引用(因为println!是使用的参数的引用), 从而匿名函数本身不需要参数列表。这样一来,我们每次通过变量f调用这个匿名函数时,都可以打印出abc

所有权移动 - move

但是这存在一个问题,匿名函数中只是借用了变量s的引用,如果变量s一旦超出作用域而被销毁, f中的引用就成为了一个悬空指针,这是Rust编译器所不允许的。

为了解决这个问题, 闭包也支持使用move关键字,来强制的将闭包中使用的任何变量移动到自身的作用域中并获取他们的所有权,而不再只是借用。

let s = "abc".to_string();
let f = move || {println!("{}", s);
};f();

这样一来s的所有权便被闭包拥有,它将一直存在,直至闭包本身超出作用域被销毁为止。我们可以把这个闭包传递给另一个线程,或者作为函数的返回值返回,等等。

在迭代器中使用闭包

如果想在迭代器中进行一些函数式的编程,对迭代变量进行处理,闭包也是真香。

let mut v = vec![2, 4, 6];
v.iter().map(|x| x * 3).filter(|x| *x > 10).fold(0, |acc, x| acc + x)

上面的代码中,对一个向量调用iter()函数,获得了一个迭代器,将对这个向量中的每个值进行迭代。然后就可以多种多样的使用到闭包的方法了。

  • map(): 对向量中每个项都乘以3;
  • filter(): 丢弃向量中不大于10的项;
  • fold(): 将筛选后的向量中的所有的值相加求和;

小结

本章介绍了Rust中闭包的概念和使用场景,已经如何将变量的所有权转移到闭包中。下一章我们将讨论Rust的多线程。

这篇关于Rust语言入门教程(十四) - 闭包Closure的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/436658

相关文章

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

C 语言的基本数据类型

C 语言的基本数据类型 注:本文面向 C 语言初学者,如果你是熟手,那就不用看了。 有人问我,char、short、int、long、float、double 等这些关键字到底是什么意思,如果说他们是数据类型的话,那么为啥有这么多数据类型呢? 如果写了一句: int a; 那么执行的时候在内存中会有什么变化呢? 橡皮泥大家都玩过吧,一般你买橡皮泥的时候,店家会赠送一些模板。 上

【Rust练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m