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
参考链接
https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-panic-recover/
https://juejin.cn/post/6844903936508297223