感想来源:
《Rust圣经》の闭包
文章目录
前言
闭包函数式编程范式的重要且优雅的实践,Rust作为一门现代化的编程语言,自然会吸收这种优秀设计,而在Rust中,由于可变性设计和借用检查机制,会使得Rust中闭包相对其他编程语言有更多理解难点。本文旨在用演绎的方式,辨析Rust中的闭包:Fn、FnOnce和FnMut
一、对闭包的基本认识
闭包的英文是closure,如果你从来没听过这个名词,可以简单理解,闭包就是一种特殊的函数
,由于可以捕获环境变量,像一个包一样,环境变量捕获,所以称之闭包。以下是两段代码来解释什么是闭包
//普通函数
fn func_example(x:i32)->i32{
x}
//闭包
|x:i32|->i32{
x};
闭包直观的特点:
- 不需要使用fn提示,正常函数需要fn提示,也没有函数签名,在C#或者Java中称为匿名函数
- 提示函数参数的部分再使用"()".,而是使用“||” ,这个符号,所以我个人也叫它直接函数;另外,不需要函数签名,直接定义函数体,也很符合这个称呼。
那么,所谓的捕获环境变量是怎么一回事?让我们看代码
//定义一个捕获环境变量「num」
let num=1;
//定义一个函数体中使用了环境变量num的闭包
let closure=|addend:i32|->i32 {
num+addend};
//调用闭包
let result= closure(1);
证明一下,普通函数的函数体不能直接使用环境变量
以上例子我们可以看出:
- 闭包的所谓捕获就是
在闭包的花括号使用到了环境变量
,普通函数无法捕获环境变量,只能通过通过正常传参。你可以把“()”或者"| |“想象成一张嘴,是参数的入口,而闭包不一样的地方是它的”{ }"部分是另一张嘴。 - 闭包可以赋值给变量
closure
,其实定义一个普通函数也是这样赋值的 - 闭包赋值给变量
closure
之后,变量closure
就具备函数签名一样的特点,可以使用closure(1)
这样的形式调用闭包。
二、闭包的作用
在对闭包建立了初步认识之后,我们会想,为什么要设计闭包这种特殊的函数?
//需求场景:写一个函数模拟做面点给家人吃的整个流程
fn cook(){
//步骤1:烧水
//步骤2: 蒸屉里放饺子
//步骤3: 端给家人吃
}
以上场景中,如果要做两道面点,那我得写两个cook函数
,但是步骤一和步骤三其实是一样的,这样就存在代码冗余。有了闭包就可以这样做
//需求场景:写一个函数模拟做面点给家人吃的整个流程
fn cook