defer特性

  • 关键字defer用于注册延迟调用。
  • 这些调用直到return前才被执。因此,可以用来做资源清理。
  • 多个defer语句,按先进后出的方式执行。
  • defer语句中的变量,在defer声明时就决定了。

defer用途

  • 关闭文件句柄
  • 锁资源释放
  • 数据库连接释放

defer语句使用说明

  • defer实现类似于栈,先进后出
  • 而且是在函数执行完成到return返回之间调用

defer 执行时机

  • 在 Go 语言的函数中 return 语句在底层并不是原子操作,它分为给返回值赋值和 RET 指令两步。
  • 而 defer 语句执行的时机就在返回值赋值操作后,RET 指令执行前。
    具体如下图所示:

defer陷阱 碰上闭包
也就是说函数正常执行,由于闭包用到的变量 i 在执行的时候已经变成4,所以输出全都是4

func main() {
	var whatever [5]struct{}
	for i := range whatever {
		defer func() { fmt.Println(i) }()
	}
}
/*
4
4
4
4
4
 */

defer 、recover 实现异常处理

  • recover()必须搭配 defer 使用
  • defer 一定要在可能引发 panic 的语句之前定义
func readFile(fileName string) error {
	if fileName == "main.go" {
		return nil
	}
	return errors.New("读取文件错误")
}
func fn3() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err) // 读取文件错误
		}
	}()
	var err = readFile("xxx.go")
	if err != nil {
		panic(err)      // panic 导致程序崩溃,异常退出
	}
	fmt.Println("继续执行")
}

func main() {
	fn3()
}