go语言 defer 你不知道的秘密!
2015-12-06 21:59
615 查看
go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱哦.我们先来看几个例子.
例一: defer 是先进后出
这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法玩了.
这个输出应该很明显,就是4 3 2 1 0
例二: defer 碰上闭包
这个输出可能会超出某些人的意料,结果是4 4 4 4 4
其实go说的很清楚,我们一起来看看go spec如何说的
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
也就是说函数正常执行,由于闭包用到的变量i在执行的时候已经变成4,所以输出全都是4.
例三: defer f.Close
这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子.
这个输出并不会像我们预计的输出c b a,而是输出c c c
可是按照前面的go spec中的说明,应该输出c b a才对啊.
那我们换一种方式来调用一下.
例四: 像例一一样的调用
这个时候输出的就是c b a
当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a
例五:看似多此一举的声明
通过以上例子,结合
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
这句话.可以得出下面的结论:
defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行.也就是复制了一份.但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待.
例一: defer 是先进后出
这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法玩了.
func main() { var whatever [5]struct{} for i := range whatever { defer fmt.Println(i) } }
这个输出应该很明显,就是4 3 2 1 0
例二: defer 碰上闭包
func main() { var whatever [5]struct{} for i := range whatever { defer func() { fmt.Println(i) }() } }
这个输出可能会超出某些人的意料,结果是4 4 4 4 4
其实go说的很清楚,我们一起来看看go spec如何说的
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
也就是说函数正常执行,由于闭包用到的变量i在执行的时候已经变成4,所以输出全都是4.
例三: defer f.Close
这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子.
type Test struct { name string } func (t * Test) Close(){ fmt.Println(t.name," closed"); } func main(){ ts:=[]Test{{"a"},{"b"},{"c"}} for _,t := range ts{ defer t.Close() } }
这个输出并不会像我们预计的输出c b a,而是输出c c c
可是按照前面的go spec中的说明,应该输出c b a才对啊.
那我们换一种方式来调用一下.
例四: 像例一一样的调用
type Test struct { name string } func (t * Test) Close(){ fmt.Println(t.name," closed"); } func Close(t Test){ t.Close() } func main(){ ts:=[]Test{{"a"},{"b"},{"c"}} for _,t := range ts{ Close(t) } }
这个时候输出的就是c b a
当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a
例五:看似多此一举的声明
type Test struct { name string } func (t * Test) Close(){ fmt.Println(t.name," closed"); } func main(){ ts:=[]Test{{"a"},{"b"},{"c"}} for _,t := range ts{ t2:=t t2.Close() } }
通过以上例子,结合
Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.
这句话.可以得出下面的结论:
defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行.也就是复制了一份.但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待.
相关文章推荐
- Go语言使用PostgreSQL数据库
- go中的闭包
- Go语言中使用SQLite数据库
- Go语言中使用MySql数据库
- 一个Ip2long函数,通过调用go tool pprof分析,竟发现内存分配了3G
- Scrambled Polygon(凸多边形,斜率)
- Link-state routing algorithm simulation
- HDU 3966 Aragorn's Story(树链剖分+线段树)
- Golang安装
- BestCode_Round65_C题(线段树)
- 理解Golang包导入
- Django Generic Display View
- golang---利用反射机制对结构体进行循环赋值
- django最简单表单入门
- Google Play 2015年度最佳游戏与应用公布
- Google Play 2015年度最佳游戏与应用公布
- 杨小麦OC之旅--Category添加属性
- Mangos Zero 编译安装
- HibernateTemplate、HibernateDaoSupport两种方法实现增删改查Good
- poj Scrambled Polygon 2007 (凸包基础点排序)