我们知道defer会在函数结束时执行,那么首先思考两个问题:
- 如果有多个defer,执行顺序是怎样的?
- defer是在return之前还是之后执行的?如果defer执行的内容对返回值进行了修改,return结果是否会改变?
defer执行顺序
通过下面这个个例子,我们看下defer的执行顺序:
package main
import (
"fmt"
)
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")
}()
}
执行结果为:
test defer2
test defer1
main defer2
main defer1
我们发现defer就像一个LIFO的栈,后defer的会先执行,且在函数退出时才会执行。
defer与return的执行顺序
首先看个例子:
package main
import (
"fmt"
)
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: 0
test函数的返回值为0,defer里面的i++操作好像对返回值并没有什么影响。
这是否表示“return i”执行结束以后才执行defer呢?
非也!再看下面的例子:
package main
import (
"fmt"
)
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之后,且返回值返回给调用方之前。
至于第一个例子中test函数返回值不是1的原因,还涉及到函数匿名返回值与命名返回值的差异,以后再单独分析。
结论
- defer的执行顺序为:后defer的先执行。
- defer的执行顺序在return之后,但是在返回值返回给调用方之前,所以使用defer可以达到修改返回值的目的。