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()
}