概述
一个 defer
语句就是一个普通的函数或方法调用。 defer
语句保证了不论是在正常情况下 (return 返回), 还是非正常情况下 (发生错误, 程序终止),函数或方法都能够执行。
主要特性
- • 一个函数可定义多个
defer
语句 - •
defer
表达式中的变量值在 defer
表达式定义时已经确定 - •
defer
表达式可以修改函数中的命名返回值
主要作用
- • 简化异常处理 ( 使用
defer
+ recover
),避免异常与控制流混合在一起 (try … catch … finally
) - • 在
defer
做资源释放和配置重置等收尾工作
语法规则
如果 defer
函数只有一行语句,可以省略 func() { ... }
代码块,否则就需要用 func() { ... }
代码块包起来。
多个 defer 执行顺序
如果一个函数中注册了多个 defer
函数,这些函数会按照 后进先出
的顺序执行 (和 栈
的出栈顺序一致)。也就是最后注册的 defer 函数会第一个执行,而第一个注册的 defer
函数会最后执行。
例子
函数退出前打印字符
package main
func A() {
defer println("A 函数执行完成")
println("A 函数开始执行")
}
func B() {
defer println("B 函数执行完成")
println("B 函数开始执行")
}
func main() {
A()
B()
}
// $ go run main.go
// 输出如下
/**
A 函数开始执行
A 函数执行完成
B 函数开始执行
B 函数执行完成
*/
关闭文件句柄
package main
import (
"fmt"
"os"
)
func createFile(name string) *os.File {
file, err := os.Create(name)
if err != nil {
panic(err)
}
return file
}
func writeFile(file *os.File) {
n, err := file.WriteString("hello world")
if err != nil {
panic(err)
} else {
fmt.Printf("成功写入 %d 个字符\n", n)
}
}
func closeFile(file *os.File) {
err := file.Close()
if err != nil {
panic(err)
}
}
func main() {
file := createFile("/tmp/defer_test.txt")
defer closeFile(file) // 获取到文件句柄后,第一时间注册 defer 函数
writeFile(file)
}
// $ go run main.go
// 输出如下
/**
成功写入 11 个字符
*/
// $ cat /tmp/defer_test.txt
// 输出如下
/**
hello world
*/
多个 defer 函数
package main
func A() {
defer println("第 1 个 defer 函数")
defer func() { // 这里为了演示 func() { ... } 的语法
defer println("第 2 个 defer 函数")
}()
defer println("第 3 个 defer 函数")
println("A 函数开始执行")
}
func main() {
A()
}
// $ go run main.go
// 输出如下
/**
A 函数开始执行
第 3 个 defer 函数
第 2 个 defer 函数
第 1 个 defer 函数
*/
reference
- 1. Go 圣经 (https://book.douban.com/subject/27044219)