1. 什么是闭包

闭包是由函数和与其相关的引用环境组合而成的实体在实现深约束时,需要创建一个能显式表示引用环境的东西,并将它与相关的子程序捆绑在一起,这样捆绑起来的整体被称为闭包。函数 + 引用环境 = 闭包。

2. 闭包和函数的区别

闭包只是在形式和表现上像函数,但实际上不是函数。具体区别如下:

  • 函数运行时只有一个实例,函数体被定义后就确定了,不会在执行时发生变化。
  • 闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
  • 函数本身不存储任何信息,只有与引用环境结合后形成的闭包才具有记忆性
  • 函数是编译器静态的概念,而闭包是运行期动态的概念。

3. 使用对比

开发一个简易的计数器

3.1 不使用闭包

package main
import "fmt"

func main() {
// 从一加到十
for i := 1; i< 10; i++ {
counter(i)
}
}
// 实现计数器
func counter(num int) {
sum := 0
sum += num
fmt.Printf("num: %d 结果: %d \n", num, sum)
}
/**输出:
num: 1 结果: 1
num: 2 结果: 2
num: 3 结果: 3
num: 4 结果: 4
num: 5 结果: 5
num: 6 结果: 6
num: 7 结果: 7
num: 8 结果: 8
num: 9 结果: 9
*/

由上述代码可以看出,for循环每执行一次,sum都会清零,没有实现sum累加计数。

3.2 使用闭包

package main
import "fmt"

func counterByClosure() func(num int) {
sum := 0
return func(num int) {
fmt.Printf("num: %d 相加前 sum = %d 相加后 sum = %d \n",num,sum,sum+num)
sum += num
}
}

func main() {
// 初始化闭包函数
counterFunc := counterByClosure()
fmt.Println(" --------- 再从1加到10 -------- ")
// 从1加到10
for i := 1; i<= 10; i++ {
counterFunc(i)
}
fmt.Println(" --------- 再从10加到20 -------- ")
// 再从10加到20
for i := 10; i<= 20; i++ {
counterFunc(i)
}
}
/**输出:
--------- 再从1加到10 --------
num: 1 相加前 sum = 0 相加后 sum = 1
num: 2 相加前 sum = 1 相加后 sum = 3
num: 3 相加前 sum = 3 相加后 sum = 6
num: 4 相加前 sum = 6 相加后 sum = 10
num: 5 相加前 sum = 10 相加后 sum = 15
num: 6 相加前 sum = 15 相加后 sum = 21
num: 7 相加前 sum = 21 相加后 sum = 28
num: 8 相加前 sum = 28 相加后 sum = 36
num: 9 相加前 sum = 36 相加后 sum = 45
num: 10 相加前 sum = 45 相加后 sum = 55
--------- 再从10加到20 --------
num: 10 相加前 sum = 55 相加后 sum = 65
num: 11 相加前 sum = 65 相加后 sum = 76
num: 12 相加前 sum = 76 相加后 sum = 88
num: 13 相加前 sum = 88 相加后 sum = 101
num: 14 相加前 sum = 101 相加后 sum = 115
num: 15 相加前 sum = 115 相加后 sum = 130
num: 16 相加前 sum = 130 相加后 sum = 146
num: 17 相加前 sum = 146 相加后 sum = 163
num: 18 相加前 sum = 163 相加后 sum = 181
num: 19 相加前 sum = 181 相加后 sum = 200
num: 20 相加前 sum = 200 相加后 sum = 220
*/

由于闭包函数“捕获”了和它在同一作用域的其他常量和变量,所以当闭包在任何地方被调用,闭包都可以使用这些常量或者变量。它不关心这些变量是否已经超出作用域,只要闭包还在使用这些变量,这些变量就依然存在。

4.闭包的优点

  • 加强模块化:闭包有益于模块化编程,便于以简单的方式开发较小的模块,从而提高开发速度和程序的可复用性。和没有使用闭包的程序相比,使用闭包可将模块划分得更小。
  • 抽象: 闭包是数据和行为的组合,这使得闭包具有较好的抽象能力。
  • 简化代码