defer 允许我们进行一些函数执行完成之后的收尾工作,并且代码更加简洁,如:
1. 关闭文件流
defer file.close()
2. 解锁加锁的资源
mu.lock()
defer mu.Unlock()
3. 最终打印
printHeader()
defer printFooter()
4. 关闭数据库连接
defer disconnectFromDB()
但是,很多朋友可能没有深入研究过一些问题:
defer和defer后的函数何时执行?
defer后函数中的变量何时计算?
请看下面一个例子。
package main
import "fmt"
func test1() (x int){
defer fmt.Println("in defer: x =", x)
x = 7
return 9
}
func test2() (x int) {
x = 7
defer fmt.Println("in defer x =", x)
return 9
}
func test3() (x int) {
defer func() {
fmt.Println("in defer x =", x)
}()
x = 7
return 9
}
func test4() (x int) {
defer func(n int){
fmt.Println("in defer x as parameter: x =", n)
fmt.Println("in defer x after return: x =", x)
}(x)
x = 7
return 9
}
func main() {
fmt.Println("--------------test1--------------")
test1()
fmt.Println("--------------test2--------------")
test2()
fmt.Println("--------------test3--------------")
test3()
fmt.Println("--------------test4--------------")
test4()
}
输出结果:
--------------test1--------------
in defer: x = 0
--------------test2--------------
in defer x = 7
--------------test3--------------
in defer x = 9
--------------test4--------------
in defer x as parameter: x = 0
in defer x after return: x = 9
defer的执行原理
想知道执行结果为什么是这样,那么就需要回答前面的两个问题:
1. defer和defer后的函数何时执行?
2. defer后函数中的变量何时计算?
问题1:
defer在defer关键字处执行,defer是把被defer的函数压入栈,等待return或panic后,再按先进后出的顺序执行被defer的函数。
问题2:
被defer函数的参数是在执行defer时计算的,函数中的变量的值是在函数执行时计算的。
defer及被defer函数的执行步骤:
1. 执行defer,计算函数入参的值并传递给函数,但不执行函数,而是将函数压入栈。
2. 当函数return或panic时,执行压入栈的函数(被defer的函数),此时,计算被defer的函数中变量的值。
所以,我们可以解释这种结果:
test1:传参,由于前面没有定义x,Println中形参x的值为0。
test2:同理,由于前面定义了x值为7,故形参x的值为7。
test3:由于内层函数可以访问外层函数的变量,当外层函数return后,读取x的值为9。
test4:传参,由于前面n未定义,故n为0;同test3,x的值为9。