1、Go语言支持闭包
2、Go语言能通过escape analyze识别出变量的作用域,自动将变量在堆上分配。将闭包环境变量在堆上分配是Go实现闭包的基础。
3、返回闭包时并不是单纯返回一个函数,而是返回了一个结构体,记录下函数返回地址和引用的环境中的变量地址。
用途
示例一
package mainimport "fmt"func adder() func(int) int {sum := 0return func(x int) int {fmt.Printf("sum addr=%p, x addr=%p\n", &sum, &x)sum += xreturn sum}}func main() {pos, neg := adder(), adder()fmt.Printf("pos addr=%p, neg addr=%p\n", &pos, &neg)for i := 0; i < 10; i++ {fmt.Println(pos(i),neg(-2*i),)}}
输出如下:
pos addr=0xc000006028, neg addr=0xc000006030sum addr=0xc0000180d8, x addr=0xc0000180f8sum addr=0xc0000180f0, x addr=0xc0000181200 0sum addr=0xc0000180d8, x addr=0xc000018130sum addr=0xc0000180f0, x addr=0xc0000181381 -2sum addr=0xc0000180d8, x addr=0xc000018160sum addr=0xc0000180f0, x addr=0xc0000181683 -6sum addr=0xc0000180d8, x addr=0xc000018190sum addr=0xc0000180f0, x addr=0xc0000181986 -12sum addr=0xc0000180d8, x addr=0xc0000181c0sum addr=0xc0000180f0, x addr=0xc0000181c810 -20sum addr=0xc0000180d8, x addr=0xc0000181f0sum addr=0xc0000180f0, x addr=0xc0000181f815 -30sum addr=0xc0000180d8, x addr=0xc000018220sum addr=0xc0000180f0, x addr=0xc00001822821 -42sum addr=0xc0000180d8, x addr=0xc000018250sum addr=0xc0000180f0, x addr=0xc00001825828 -56sum addr=0xc0000180d8, x addr=0xc000018280sum addr=0xc0000180f0, x addr=0xc00001828836 -72sum addr=0xc0000180d8, x addr=0xc0000182b0sum addr=0xc0000180f0, x addr=0xc0000182b845 -90
因为pos和neg都调用了adder()参数,返回了不同的闭包,所以sum在堆上分配的地址空间也不同;
所以针对pos(i)是求sum=sum+i,即0+0=0,0+1=1, 1+2=3,3+3=6…
neg是求sum=sum+(-2i),即0+(-20)=0,0+(-21)=-2,-2+(-22)=-6….
示例二
package mainimport "fmt"func main() {var flist []func()for i := 0; i < 3; i++ {fmt.Printf("A: addr=%p, value=%d\n", &i, i)flist = append(flist, func() {fmt.Printf("B: addr=%p, value=%d\n", &i, i)})}for _, f := range flist {f()}}
输出如下:
A: addr=0xc0000180d8, value=0A: addr=0xc0000180d8, value=1A: addr=0xc0000180d8, value=2B: addr=0xc0000180d8, value=3B: addr=0xc0000180d8, value=3B: addr=0xc0000180d8, value=3
这个比较好理解,三个匿名函数闭包中的i是同一个变量i,在堆上是同一个,最后i的值为3,所以三次都输出3。
示例三
package mainimport "fmt"func main() {var flist []func()for i := 0; i < 3; i++ {//给i变量重新赋值i := ifmt.Printf("A: addr=%p, value=%d\n", &i, i)flist = append(flist, func() {fmt.Printf("B: addr=%p, value=%d\n", &i, i)})}for _, f := range flist {f()}}
输出结果如下:
A: addr=0xc0000180d8, value=0A: addr=0xc0000180f8, value=1A: addr=0xc000018118, value=2B: addr=0xc0000180d8, value=0B: addr=0xc0000180f8, value=1B: addr=0xc000018118, value=2
i被重新赋值,传入闭包函数的i为新的地址,所以三个闭包函数分别为1,2,3
