defer 是G o语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过 return 正常结束或者 panic 导致的异常结束)执行,它会经常被用于关闭文件描述符、关闭数据库连接以及解锁资源等。
func main() {
fmt.Println("start")
for i := 0; i < 5; i++ {
defer fmt.Println(i)
}
fmt.Println("end")
/*
输出结果:
start
end
4
3
2
1
0
}
defer 后面跟的内容除了可以是一行语句以外,也可以是一个函数/匿名函数。
func closeAll() {
fmt.Println("close all 1 !")
}
func main() {
fmt.Println("start")
defer closeAll()
defer func() { fmt.Println("close all 2") }()
fmt.Println("end")
}
输出结果
当一个函数在执行过程中出现了异常或遇到 panic(),正常语句就会立即终止,然后执行 defer 语句,再报告异 常信息,最后退出 goroutine。如果在 defer 中使用了 recover() 函数,则会捕获错误信息,使该错误信息终止报告。
func main() {
fmt.Println("start")
defer func() { fmt.Println("close all") }()
panic("ERROR")
fmt.Println("end")
}
输出结果为
start
close all
panic: ERROR
goroutine 1 [running]:
main.main()
/Users/zhangyanfei/work_go/go-training/2-code-organize/defer/main.go:12 +0xb7
Process finished with exit code 2
注意:panic 只会触发当前 Goroutine 的延迟函数调用;
recover 只有在 defer 函数中调用才会生效
fmt.Println("start")
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered in f", r)
}
}()
panic("ERROR")
fmt.Println("end")
panic之后虽然end同样没有输出,但是和没有recover的demo相比,程序并没有异常退出。
start
Recovered in f ERROR
Process finished with exit code 0