前面的记当里我讲过:
1.当有多个defer时候,执行顺序为“后进先出”
2.defer、return、返回值(命名返回值和无名返回值的结果也是不同的
)return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出
如果函数的返回值是无名的,则go语言会在执行return的时候会执行一个类似创建一个临时变量作为保存return值的动作,而有名返回值的函数,由于返回值在函数定义的时候已经将该变量进行定义,在执行return的时候会先执行返回值保存操作,而后续的defer函数会改变这个返回值(虽然defer是在return之后执行的,但是由于使用的是函数自身定义的变量(相当于这个变量和函数绑定在一起了),所以执行defer操作后对该变量的修改会影响到return的值
example1: 不带命名返回值的函数
package main
import "fmt"
func main() {
fmt.Println("return:",test())
}
func test() int {
var i int
defer func() {
i++
fmt.Println("defer1:",i)
}()
defer func() {
i++
fmt.Println("defer2:",i)
}()
return i
}
打印结果:
defer2: 1
defer1: 2
return: 0
example2:
package main
import "fmt"
func main() {
fmt.Println("return:",test())
}
func test() (i int) {
defer func() {
i++
fmt.Println("defer1:",i)
}()
defer func() {
i++
fmt.Println("defer2:",i)
}()
return i
}
打印结果:
defer2: 1
defer1: 2
return: 2
return和返回值的运行机制:
第一个例子:
相当于:
var i int
s :=i
return s
所以return执行时实际生成了一个临时变量来存储i的值,再把这个临时变量s返回,此时s的值为0
程序发现还有defer需要执行,所以逆序执行了defer2和defer1,在执行的过程中,i的值也在发生变化,因为此时的defer2和defer1就好像是一个闭包,一直在传递这个变量i
第二个例子
也是跟第一个例子一样先执行return i 的值,每一次的执行defer,实际上都是在操作这个返回值i,所以最后结果也被更新由函数返回
要注意两者的差异。