前面的记当里我讲过:
1.当有多个defer时候,执行顺序为“后进先出”
2.defer、return、返回值(命名返回值和无名返回值的结果也是不同的)return最先执行,return负责将结果写入返回值中;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出

如果函数的返回值是无名的,则go语言会在执行return的时候会执行一个类似创建一个临时变量作为保存return值的动作,而有名返回值的函数,由于返回值在函数定义的时候已经将该变量进行定义,在执行return的时候会先执行返回值保存操作,而后续的defer函数会改变这个返回值(虽然defer是在return之后执行的,但是由于使用的是函数自身定义的变量(相当于这个变量和函数绑定在一起了),所以执行defer操作后对该变量的修改会影响到return的值

example1: 不带命名返回值的函数

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("return:",test())
  5. }
  6. func test() int {
  7. var i int
  8. defer func() {
  9. i++
  10. fmt.Println("defer1:",i)
  11. }()
  12. defer func() {
  13. i++
  14. fmt.Println("defer2:",i)
  15. }()
  16. return i
  17. }

打印结果:
defer2: 1
defer1: 2
return: 0

example2:

  1. package main
  2. import "fmt"
  3. func main() {
  4. fmt.Println("return:",test())
  5. }
  6. func test() (i int) {
  7. defer func() {
  8. i++
  9. fmt.Println("defer1:",i)
  10. }()
  11. defer func() {
  12. i++
  13. fmt.Println("defer2:",i)
  14. }()
  15. return i
  16. }

打印结果:
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,所以最后结果也被更新由函数返回

要注意两者的差异。