閉包是在其詞法上下文中引用了自由變量的函數(shù)〉窍拢或者說是函數(shù)和其引用的環(huán)境的組合體。
func test(x int) func() {
return func() {
println(x)
}
}
func main() {
f := test(123)
f()
}
輸出:
123
如上邊案例:test 返回的匿名函數(shù)會引用上下文環(huán)境變量x。當該函數(shù)在main中執(zhí)行時爱致,它依然可以正確讀取x的值,這種現(xiàn)象稱作閉包寒随。
1.閉包的延遲求值特性
func test() []func() {
var s []func()
for i := 0; i<2; i++ {
s = append(s, func() { //將多個匿名函數(shù)添加到列表
println(&i, i)
})
}
return s //返回匿名函數(shù)列表
}
func main() {
for _, f := range test() { //迭代執(zhí)行所有匿名函數(shù)
f()
}
}
輸出:
0xc000014078 2
0xc000014078 2
我們可以看出輸出輸出結(jié)果并不是我們想象中的樣子糠悯,因為,for循環(huán)復用局部變量i妻往,那么每次添加的匿名函數(shù)引用的自然是同一變量互艾。添加操作僅僅是將匿名函數(shù)放入列表,并未執(zhí)行讯泣。因此當main函數(shù)執(zhí)行這些函數(shù)時纫普,它們讀取的是環(huán)境變量i最后一次循環(huán)的值。
那么有什么解決方式么好渠?可以這樣昨稼,每次用不同的環(huán)境變量或參數(shù)復制,讓各自閉包的環(huán)境各不相同晦墙。
改造下:
func test() []func() {
var s []func()
for i := 0; i<2; i++ {
x := i //每次循環(huán)都重新定義
s = append(s, func() {
println(&x, x)
})
}
return s
}
func main() {
for _, f := range test() {
f()
}
}
輸出:
0xc000014078 0
0xc000014090 1