1. 什么是闭包

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

2. 闭包和函数的区别

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

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

3. 使用对比

开发一个简易的计数器

3.1 不使用闭包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 使用闭包

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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.闭包的优点

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