GO里的defer关键字
defer用于资源的释放,会在函数返回之前进行调用
1 | f,err := os.Open(filename) |
如果有多个defer,调用顺序类似于栈,越后面的defer表达式越先被调用
defer使用注意
示例
例1:
1 | func f() (result int) { |
正确结果返回1,而不是0
可改写成:
1 | func f() (result int) { |
所以返回是1
例2:
1 | func f() (r int) { |
返回结果是5,不是10
可改写成:
1 | func f() (r int) { |
所以结果是5
例3:
1 | func f() (r int) { |
结果是1,不是6
可以改写成:
1 | func f() (r int) { |
所以结果是1
原理
return xxx这一条语句并不是一条原子指令!
函数返回的过程是这样的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。
defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。
defer的实现
defer跟go类似
调用runtime.deferproc而不是runtime.newproc
在defer出现的地方,插入了指令call runtime.deferproc,然后在函数返回之前的地方,插入指令call runtime.deferreturn。
普通函数汇编
1 | add xx SP |
defer
1 | call runtime.deferreturn, |
goroutine的控制结构中,有一张表记录defer,调用runtime.deferproc时会将需要defer的表达式记录在表中,而在调用runtime.deferreturn的时候,则会依次从defer表中出栈并执行
for循环的defer
不建议这么使用
defer 先进后出