defer的用法

1.清理释放资源

由于 defer 的延迟特性,defer 常用在函数调用结束之后清理相关的资源,如:

f, _ := os.Open(filename)
defer f.Close()


2.执行 recover

被 defer 的函数在 return 之后执行,这个时机点正好可以捕获函数抛出的 panic,因而 defer 的另一个重要用途就是执行 recover。

(1.) ​​panic​​ 能够改变程序的控制流,调用 ​​panic​​ 后会立刻停止执行当前函数的剩余代码,并在当前 Goroutine 中递归执行调用方的 ​​defer​​;

(2.) ​​recover​​ 可以中止 ​​panic​​ 造成的程序崩溃。它是一个只能在 ​​defer​​ 中发挥作用的函数,在其他作用域中调用不会发挥作用;

(3.) panic 只会触发当前 Goroutine 的 defer;

(4.) recover 只有在 defer 中调用才会生效;

(5.)panic 允许在 defer 中嵌套多次调用;

// 打印堆栈信息
defer func() {
if err := recover(); err != nil {
Log.Error("server panic,err:%v", err)
for i := 0; ; i++ {
pc, file, line, ok := runtime.Caller(i)
if !ok {
break
}
Log.Error("server panic,pc:%v\n,file:%v\n,line:%v\n", pc, file, line)
}
}
}()


3.后进先出

多个defer出现的时候,它是一个“栈”的关系,也就是先进后出。一个函数中,写在前面的defer会比写在后面的defer调用的晚。

defer func() { fmt.Println("1") }()
defer func() { fmt.Println("2") }()
defer func() { fmt.Println("3") }()

// 执行结果:3 2 1


4.修改带名称的返回值

return之后的语句先执行,defer后的语句后执行

func c() (i int) {
defer func() { i++ }()
return 1
}

// 返回值:2




【励志篇】: 古之成大事掌大学问者,不惟有超世之才,亦必有坚韧不拔之志。