先看一段代码,脱离代码讲闭包,太干了。
package main
import "fmt"
func main() {
a := Adder()
fmt.Println(a(1))
fmt.Println(a(2))
fmt.Println(a(3))
}
func Adder() func(int) int { // 累加器:这里从10开始累加
var sum int = 10
return func(x int) int {
sum = sum + x
return sum
}
}
主要看这里的Adder 函数 部分,这里面有2个函数,大的函数Adder 包了一个内部的匿名函数。我们来这个两个函数起一个小名好了,外面大一点的我们叫他outer,里面的匿名函数,我们就叫他inner。
现在的情况是:outer 外部函数 返回了inner内部函数,在outer调用完成后,inner被main中的a变量接住了,我们同时发现 inner 使用了outer函数的局部变量地址指针一直没有消亡。
对于这种代码现象就是一个的closure。
使用时发现的情况时:a(1),a(2),a(3) 发现 每次 sum的值都是从前一个a函数基础上得到sum值进行累加的,而不是回到10进行累加的。
Outer中的局部变量sum,不会随着outer的返回而从栈上销毁它。相反,它会一直保留着sum保存的堆地址的指针,并会一直等待着我们去使用它。
非要我说个原因的话,我就尝试解说一通:
由于Adder() 执行完毕返回了一个匿名函数,把其赋值给了变量a,由于a引用了该匿名函数,正是由于a的持有,则匿名函数使用到的局部变量sum ,就不该随着adder 执行完毕就消亡,即sum变量不死 ,所以sum变量中保存的堆堆地址空间就一直存在。
对于闭包的如何分析:
主要要看返回的函数,它引用了哪些局部变量,这些局部变量和返回的函数共同构成了我们的闭包整体。
可以把闭包当成Java中的类,而sum局部变量就是字段,返回的函数 和 字段 sum 一起构成了类。
刚刚接触GO的第三天,水平有限,如果真的讲的有问题,欢迎留言,互相进步,共同学习。
虽是一家之言,也希望你有所收获,加油!