defer是Go提供用于注册延迟调用的机制,让函数或语句可以再当前函数执行完成之后(包括return语句正常结束或者panic导致的异常结束)执行。defer常用于资源回收的场景,比如打开/关闭连接,加锁或释放锁等。
不同的defer执行顺序
func main() {
defer fmt.Println("main defer1")
test()
defer fmt.Println("main defer2")
}
func test() () {
defer func() {
fmt.Println("test defer1")
}()
defer func() {
fmt.Println("test defer2")
}()
}
输出结果:
执行流程:
defer执行有两个条件:
- defer所在的函数必须先执行完成
- 按照栈的FILO的方式执行。
因此,test函数先于main函数结束,因此test函数中defer先执行。栈是FILO,因此打印
test defer2
->test defer1
。test函数执行完成之后,main函数执行完成之后,执行main函数的defer操作,同样按照FILO的方式执行,因此打印main defer2
->main defer1
defer与return的执行顺序
理解上面defer的执行过程,就很容易理解defer与return的执行顺序
func main() {
ret := test()
fmt.Println("test return:", ret)
}
func test() ( int) {
var i int
defer func() {
i++ //defer里面对i增1
fmt.Println("test defer, i = ", i)
}()
return i
}
执行结果:
test defer,i=1
test return: 1
执行顺序:
- test函数先执行,test执行返回0,之后执行defer函数,打印
test defer,i=1
- test函数执行完成之后,main函数打印
test return: 0
再来看下面的代码:
func main() {
ret := test()
fmt.Println("test return:", ret)
}
//返回值改为命名返回值
func test() (i int) {
//var i int
defer func() {
i++
fmt.Println("test defer, i = ", i)
}()
return i
}
执行结果:
test defer, i = 1
test return: 1
这次test函数的返回值变成了1,defer里面i++
修改了返回值,因此defer执行的时机是return之后,但是在返回值返回给调用方之前。