转自原文链接
https://www.golangtc.com/t/50d07e11320b521f59000012
闭包虽然在开发中用得不多,但是理解意义还是对于编程有帮助的
版本1:
package main
import "fmt"
func main() {
var fn [10]func()
for i := 0; i < len(fn); i++ {
fn[i] = func() {
fmt.Println(i)
}
}
for _, f := range fn {
f()
}
}
结果如下:
10
10
10
10
10
10
10
10
10
10
分析:mian()与func()[]数组构成闭包使用同一个i变量main函数不退出i变量一直存在,f()执行时调用打印语句此时变量i为10。 版本2:
package main
import "fmt"
func main() {
var fn [10]func()
for i := 0; i < len(fn); i++ {
fn[i] = func() {
fmt.Println(i)
}
}
for i := 0 ; i < len(fn); i++ {
fn[i]()
}
}
结果如下:
10
10
10
10
10
10
10
10
10
10
分析:与版本1对比使用显示的i变量做为迭代,但是闭包空间中的i与调用迭代中的i指向内存不同(生存空间也不同)所以使用闭包空间中的i作为打印值为10。 版本3:
package main
import "fmt"
func main() {
var fn [10]func()
for i := 0; i < len(fn); i++ {
fn[i] = func() {
fmt.Println(i)
}
}
for j := 0 ; j < len(fn); j++ {
fn[j]()
}
}
结果如下:
10
10
10
10
10
10
10
10
10
10
分析:为证明版本2中的分析说法,使用j作为迭代变量,同样打印的10. 版本4:
package main
import "fmt"
func main() {
var fn [10]func()
var i int
for i = 0; i < len(fn); i++ {
fn[i] = func() {
fmt.Println(i)
}
}
for i = 0; i < len(fn); i++ {
fn[i]()
}
}
结果如下:
0
1
2
3
4
5
6
7
8
9
分析:在main()中声明变量i此时i的生存空间扩大到了main()函数,两次迭代使用同一个i变量。故在第二次迭代时i的迭代当前值会作为打印参数。 版本5:
package main
import "fmt"
func main() {
var fn [10]func()
for i := 0; i < len(fn); i++ {
fn[i] = make_fn(i)
}
for _, f := range fn {
f()
}
}
func make_fn(i int) func() {
return func() {
fmt.Println(i)
}
}
结果如下:
0
1
2
3
4
5
6
7
8
9
分析:在main()函数外定义单独的闭包函数,构成独立的闭包单元,隔离不同func()[]中不同的func()。隔离与独立才是闭包的意义所在,一个表示一系列状态的集合不该在外部为显示通知改变时改变其内部状态。 版本6:
package main
import "fmt"
func main() {
var fn [10]func(int)
for i := 0; i < len(fn); i++ {
fn[i] = make_fn()
}
for i, f := range fn {
f(i)
}
}
func make_fn() func(i int) {
return func(i int) {
fmt.Println(i)
}
}
结果如下:
0
1
2
3
4
5
6
7
8
9
分析:最后这个版本应该为最佳,gotour中的闭包示例使用的正是此中表示方式。