一直用java没用过闭包(我还很菜,可能java也能闭包我不会罢了,希望有人回帖指点),刚接触golang对其闭包机制也挺疑惑。下面写了六个版本的闭包小谈一下。有几个版本摘自别家,看了有段时间我一时不记得来源了很对不起作者了!
版本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中的闭包示例使用的正是此中表示方式。
能力有限只能写这么多了,本人第一次发博支持一下,有意见直说谢谢(漫骂亦可)!
有疑问加站长微信联系(非本文作者)