Go defer 的一些注意事项
Posted 看,未来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go defer 的一些注意事项相关的知识,希望对你有一定的参考价值。
文章目录
defer 碰上闭包
package main
import "fmt"
func main()
var whatever [5]struct
for i := range whatever
defer func() fmt.Println(i) ()
4
4
4
4
4
package main
import "fmt"
func f(i int)
fmt.Println(i)
func main()
var whatever [5]struct
for i := range whatever
defer f(i)
4
3
2
1
0
其实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 碰上指针
这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子.
package main
import "fmt"
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 closed
c closed
c closed
这个输出并不会像我们预计的输出c b a,而是输出c c c
可是按照前面的go spec中的说明,应该输出c b a才对啊.
那我们换一种方式来调用一下.
package main
import "fmt"
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
defer Close(t)
c closed
b closed
a closed
这个时候输出的就是c b a
当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a
看似多此一举的声明
package main
import "fmt"
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
defer t2.Close()
c closed
b closed
a closed
结论
通过以上例子,结合
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 注册,按 FILO 次序执行 ( 先进后出 )。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。
package main
func test(x int)
defer println("a")
defer println("b")
defer func()
println(100 / x) // div0 异常未被捕获,逐步往外传递,最终终止进程。
()
defer println("c")
func main()
test(0)
c
b
a
panic: runtime error: integer divide by zero
goroutine 1 [running]:
main.test.func1()
C:/Users/Administrator/Desktop/go/main.go:7 +0x65
main.test(0xc00003e000?)
C:/Users/Administrator/Desktop/go/main.go:10 +0x96
main.main()
C:/Users/Administrator/Desktop/go/main.go:12 +0x1b
*滥用 defer 可能会导致性能问题,尤其是在一个 “大循环” 里。
以上是关于Go defer 的一些注意事项的主要内容,如果未能解决你的问题,请参考以下文章