闭包是在其词法上下文中引用了自由变量的函数。或者说是函数和其引用的环境的组合体。
func test(x int) func() {
return func() {
println(x)
}
}
func main() {
f := test(123)
f()
}
输出:
123
如上边案例:test 返回的匿名函数会引用上下文环境变量x。当该函数在main中执行时,它依然可以正确读取x的值,这种现象称作闭包。
1.闭包的延迟求值特性
func test() []func() {
var s []func()
for i := 0; i<2; i++ {
s = append(s, func() { //将多个匿名函数添加到列表
println(&i, i)
})
}
return s //返回匿名函数列表
}
func main() {
for _, f := range test() { //迭代执行所有匿名函数
f()
}
}
输出:
0xc000014078 2
0xc000014078 2
我们可以看出输出输出结果并不是我们想象中的样子,因为,for循环复用局部变量i,那么每次添加的匿名函数引用的自然是同一变量。添加操作仅仅是将匿名函数放入列表,并未执行。因此当main函数执行这些函数时,它们读取的是环境变量i最后一次循环的值。
那么有什么解决方式么?可以这样,每次用不同的环境变量或参数复制,让各自闭包的环境各不相同。
改造下:
func test() []func() {
var s []func()
for i := 0; i<2; i++ {
x := i //每次循环都重新定义
s = append(s, func() {
println(&x, x)
})
}
return s
}
func main() {
for _, f := range test() {
f()
}
}
输出:
0xc000014078 0
0xc000014090 1