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

相关文章

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go语言使用Gin处理路由参数和查询参数

《Go语言使用Gin处理路由参数和查询参数》在WebAPI开发中,处理路由参数(PathParameter)和查询参数(QueryParameter)是非常常见的需求,下面我们就来看看Go语言... 目录一、路由参数 vs 查询参数二、Gin 获取路由参数和查询参数三、示例代码四、运行与测试1. 测试编程路

Python库 Django 的简介、安装、用法入门教程

《Python库Django的简介、安装、用法入门教程》Django是Python最流行的Web框架之一,它帮助开发者快速、高效地构建功能强大的Web应用程序,接下来我们将从简介、安装到用法详解,... 目录一、Django 简介 二、Django 的安装教程 1. 创建虚拟环境2. 安装Django三、创

Go语言使用net/http构建一个RESTful API的示例代码

《Go语言使用net/http构建一个RESTfulAPI的示例代码》Go的标准库net/http提供了构建Web服务所需的强大功能,虽然众多第三方框架(如Gin、Echo)已经封装了很多功能,但... 目录引言一、什么是 RESTful API?二、实战目标:用户信息管理 API三、代码实现1. 用户数据

Go语言网络故障诊断与调试技巧

《Go语言网络故障诊断与调试技巧》在分布式系统和微服务架构的浪潮中,网络编程成为系统性能和可靠性的核心支柱,从高并发的API服务到实时通信应用,网络的稳定性直接影响用户体验,本文面向熟悉Go基本语法和... 目录1. 引言2. Go 语言网络编程的优势与特色2.1 简洁高效的标准库2.2 强大的并发模型2.

Go语言使用sync.Mutex实现资源加锁

《Go语言使用sync.Mutex实现资源加锁》数据共享是一把双刃剑,Go语言为我们提供了sync.Mutex,一种最基础也是最常用的加锁方式,用于保证在任意时刻只有一个goroutine能访问共享... 目录一、什么是 Mutex二、为什么需要加锁三、实战案例:并发安全的计数器1. 未加锁示例(存在竞态)

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五