32、Rust 闭包 Closure

闭包( Closure ) 的出现其实是 程序员偷懒的结果,也可以说是 语言开发者为程序员送的福利

为什么这么说呢 ?

我们来看看几个 闭包 的解释:

  • 闭包就是在一个函数内创建立即调用的另一个函数。
  • 闭包是一个匿名函数。也就是没有函数名称。
  • 闭包虽然没有函数名,但可以把整个闭包赋值一个变量,通过调用该变量来完成闭包的调用。从某些方面说,这个变量就是函数名的作用。
  • 闭包不用声明返回值,但它却可以有返回值。并且使用最后一条语句的执行结果作为返回值。闭包的返回值可以赋值给变量。
  • 闭包有时候有些地方又称之为 内联函数。这种特性使得闭包可以访问外层函数里的变量。

从上面的描述中可以看出,闭包就是函数内部的一个没有函数名的内联函数。对于那些只使用一次的函数,使用闭包是最佳的代替方案。

定义闭包的语法

在介绍如何定义闭包前,我们先来看看 如何定义一个普通的函数

一个普通的函数的定义语法格式如下

fn function_name(parameters) -> return_type {
   // 函数的具体逻辑
}

从上面的描述中我们知道,闭包是一个没有函数名的内联函数。它的定义语法如下

|parameter| {
   // 闭包的具体逻辑
}

从语法格式上来看,闭包就是普通函数去掉 fn 关键字,去掉函数名,去掉返回值声明,并把一对小括号改成一对 竖线 ||。

闭包的参数是可选的,如果一个闭包没有参数,那么它的定义语法格式如下

||{
   // 闭包的具体逻辑  
}

闭包虽然没有名称,但我们可以将闭包赋值给一个变量,然后就可以通过调用这个变量来完成闭包的调用。

let closure_function = |parameter| {
   // 闭包的具体逻辑
}

因为调用闭包的语法实现了 Fn 特质,因此我们可以像调用普通函数那样,使用小括号 () 来调用闭包

closure_function(parameter);    //invoking

范例:普通的闭包

下面的代码我们定义了一个闭包用于判断传递的参数是否偶数,并把闭包赋值给变量 is_even

然后我们通过调用 is_even() 来完成闭包的调用。

fn main(){
   let is_even = |x| {
      x%2==0
   };
   let no = 13;
   println!("{} is even ? {}",no,is_even(no));
}

编译运行以上 Rust 代码,输出结果如下

13 is even ? false

范例:闭包使用外部函数可以访问的变量

闭包还可以访问它所在的外部函数可以访问的所有变量。

fn main(){
   let val = 10; 
   // 访问外层作用域变量 val
   let closure2 = |x| {
      x + val // 内联函数访问外层作用域变量
   };
   println!("{}",closure2(2));
}

编译运行以上 Rust 代码,输出结果如下

12