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
,file:%v
,line:%v
", 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

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