闭包的价值
什么是闭包
闭包是由函数以及相关引用环境组合而成的实体,一般通过在匿名函数中引用外部函数的局部变量或包全局变量组成。
闭包 = 函数+应用环境
案例
闭包对闭包外的环境引入是直接引用,编译器检测到闭包,会将闭包引用到外部变量分配到堆上。
如果函数返回的闭包引用了该函数的局部变量(参数或者函数内部变量):
* 多次调用该函数,返回的多个闭包所引用的外部变量是多个副本,原因是每次调用函数都会为局部变量分配内存
* 用一个闭包函数多次,如果该闭包修改了其引用的外部变量,则每一次调用该闭包对该外部变量都有影响,因为闭包函数共享外部引用。
实例如下:
package main
func fa(a int) func(i int) int{
return func(i int) int{
println(&a,a)
a = a + i
return a
}
}
func main(){
f:=fa(1)//f引用的外部的闭包环境包括本次函数调用的形参a的值1
g:=fa(1)//g引用的外部的闭包环境包括本次函数调用的形参a的值1
//此时f,g引用的闭包环境中的a的值斌不是同一个,而是两次函数调用产生的副本
println(f(1))
//多次调用f引用的是同一个副本a
println(f(1))
println(f(1))
//g中的a值仍然是1
println(g(1))
println(g(1))
}
运行结果:
0xc00000a028 1
2
0xc00000a028 2
3
0xc00000a028 3
4
0xc00000a040 1
2
0xc00000a040 2
3
f和g引用的是不同的a
如果一个函数调用返回的闭包引用修改了全局变量,则每次调用都会影响全局变量。如果函数返回的闭包引用的是全局变量a,则多次调用该函数返回的多个闭包引用的都是同一个a。同理,调用一个闭包多次引用的也是同一个a,此时如果闭包中修改了a值的逻辑,则每次闭包调用都会影响全局变量a的值。使用闭包是为了减少全局变量,所以闭包i引用全局变量不是好的编程方式。
实例如下:
var (
a = 0
)
func fa() func(i int) int {
return func(i int) int {
println(&a,a)
a = a+i
return a
}
}
func main() {
f := fa();
g :=fa();
println(f(1))//1
println(g(1))//2
println(g(1))//3
println(g(1))//4
}
运行结果:
0xc2e180 0
1
0xc2e180 1
2
0xc2e180 2
3
0xc2e180 3
4
闭包的本质
闭包最初的目的是减少全局变量,在函数调用的过程中隐式地传递共享变量,有其有用的一面;但是这种隐秘的共享变量的方式带来的坏处是不够直接,不够清晰,除非是非常有价值的地方,一般不建议使用闭包。对向是附有行为的是数据,而闭包是附有数据的行为,类定义时以及显式的集中定义了行为,但是闭包中的数据没有显示地集中申明的地方,这种数据和行为耦合的模型不是一种推荐的编程模式,闭包仅仅是锦上添花的东西,不是不可缺少的。