目录
1. defer 的基本功能
defer后面只能跟函数调用语句,defer把该语句执行的时间推迟到执行结束的时候
用法类似于面向对象编程语言 Java 和 C# 的 finally
语句块,它一般用于释放某些已分配的资源。
func test() {
defer fmt.Println("out test")
fmt.Println("enter test")
//todo
}
func main() {
test()
}
2. 应用场景举例
1. 关闭文件流
//open a file
defer file.Close()
2. 解锁一个加锁的资源
mu.Lock()
defer mu.Unlock()
3. 打印最终报告
printHeader()
defer printFooter()
4. 关闭数据库链接
// open a database connection
defer disconnectFromDB()
5. 使用 defer 语句实现代码追踪
6. 使用 defer 语句来记录函数的参数与返回值
3. 注意事项
1. 当有多个 defer 行为被注册时,它们会以逆序执行(类似栈,即后进先出)
func test() {
for i := 0; i < 5; i++ {
defer fmt.Println(i)
}
fmt.Println("out test")
}
结果打印如下
2. defer函数参数的计算时间点
func test(arg int) {
defer fmt.Println("defer arg is ", arg)
arg += 2000
fmt.Println("out arg is ", arg)
}
func main() {
test(100)
}
结果打印如下
可以看到 defer 语句只是延迟了执行函数的时机,并没有延迟传递参数的时机
3. 用defer调用多条函数语句
我们可以使用匿名函数来调用多条语句
func test(arg int) {
defer func() {
arg += 12
fmt.Println("defer arg is ", arg)
}()
arg += 2000
fmt.Println("out arg is ", arg)
}
func main() {
test(100)
}
执行结果如下
有趣的事情发生了,这里 defer 语句打印的结果居然是 2112 ?推测解释如下:
在这里 defer 并没有传递参数,功能只是把这个匿名函数推迟调用了而已,然后匿名函数使用了arg这个局部变量
func test(arg int) {
defer func(a int) {
a += 12
fmt.Println("defer arg is ", a)
}(arg)
arg += 2000
fmt.Println("out arg is ", arg)
}
func main() {
test(100)
}
执行结果如下
4. 使用defer函数影响宿主函数的返回值
由上面的例子我们可以知道,在函数内部使用匿名函数是可以直接使用函数内部的局部变量的(有点拗口)
那么 [ defer + 匿名函数 ] 的组合当然也可以修改函数的返回值(这是需要我们警惕的点)