小谈golang闭包

一直用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中的闭包示例使用的正是此中表示方式。

能力有限只能写这么多了,本人第一次发博支持一下,有意见直说谢谢(漫骂亦可)!

相关文章

程序目录结构 简单实现,用户登录后返回一个jwt的token,下次请求带上token请求用户信息接口并返回信息...
本篇博客的主要内容是用go写一个简单的Proof-of-Work共识机制,不涉及到网络通信环节,只是一个本地的简...
简介 默克尔树(MerkleTree)是一种典型的二叉树结构,其主要特点为: 最下面的叶节点包含存储数据或其...
接下来学习并发编程, 并发编程是go语言最有特色的地方, go对并发编程是原生支持. goroutine是go中最近本...
先普及一下, 什么是广度优先搜索 广度优先搜索类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶...
第一天: 接口的定义和实现 第二天: 一. go语言是面向接口编程. 在学习继承的时候说过, go语言只有封装,...