1、Go语言支持闭包
2、Go语言能通过escape analyze识别出变量的作用域,自动将变量在堆上分配。将闭包环境变量在堆上分配是Go实现闭包的基础。
3、返回闭包时并不是单纯返回一个函数,而是返回了一个结构体,记录下函数返回地址和引用的环境中的变量地址。
用途
示例一
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
fmt.Printf("sum addr=%p, x addr=%p\n", &sum, &x)
sum += x
return 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=0xc000006030
sum addr=0xc0000180d8, x addr=0xc0000180f8
sum addr=0xc0000180f0, x addr=0xc000018120
0 0
sum addr=0xc0000180d8, x addr=0xc000018130
sum addr=0xc0000180f0, x addr=0xc000018138
1 -2
sum addr=0xc0000180d8, x addr=0xc000018160
sum addr=0xc0000180f0, x addr=0xc000018168
3 -6
sum addr=0xc0000180d8, x addr=0xc000018190
sum addr=0xc0000180f0, x addr=0xc000018198
6 -12
sum addr=0xc0000180d8, x addr=0xc0000181c0
sum addr=0xc0000180f0, x addr=0xc0000181c8
10 -20
sum addr=0xc0000180d8, x addr=0xc0000181f0
sum addr=0xc0000180f0, x addr=0xc0000181f8
15 -30
sum addr=0xc0000180d8, x addr=0xc000018220
sum addr=0xc0000180f0, x addr=0xc000018228
21 -42
sum addr=0xc0000180d8, x addr=0xc000018250
sum addr=0xc0000180f0, x addr=0xc000018258
28 -56
sum addr=0xc0000180d8, x addr=0xc000018280
sum addr=0xc0000180f0, x addr=0xc000018288
36 -72
sum addr=0xc0000180d8, x addr=0xc0000182b0
sum addr=0xc0000180f0, x addr=0xc0000182b8
45 -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 main
import "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=0
A: addr=0xc0000180d8, value=1
A: addr=0xc0000180d8, value=2
B: addr=0xc0000180d8, value=3
B: addr=0xc0000180d8, value=3
B: addr=0xc0000180d8, value=3
这个比较好理解,三个匿名函数闭包中的i是同一个变量i,在堆上是同一个,最后i的值为3,所以三次都输出3。
示例三
package main
import "fmt"
func main() {
var flist []func()
for i := 0; i < 3; i++ {
//给i变量重新赋值
i := 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=0
A: addr=0xc0000180f8, value=1
A: addr=0xc000018118, value=2
B: addr=0xc0000180d8, value=0
B: addr=0xc0000180f8, value=1
B: addr=0xc000018118, value=2
i被重新赋值,传入闭包函数的i为新的地址,所以三个闭包函数分别为1,2,3