【注意】最后更新于 March 2, 2023,文中内容可能已过时,请谨慎使用。
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.闭包的优点
- 加强模块化:闭包有益于模块化编程,便于以简单的方式开发较小的模块,从而提高开发速度和程序的可复用性。和没有使用闭包的程序相比,使用闭包可将模块划分得更小。
- 抽象: 闭包是数据和行为的组合,这使得闭包具有较好的抽象能力。
- 简化代码