关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

Golang中的defer(1)

发布时间:2023-06-26 19:00:40

面试常问之defer()的执行次序


情形1

package main  func main() {   defer print(123)  defer_call()  defer print(789) //panic之后的代码不会被执行  print("不会执行到这里") }  func defer_call() {  defer func() {  print("打印前")  }()  defer func() {  print("打印中")  }()   defer print("打印后")   panic("触发异常")   defer print(666) //IDE会有提示: Unreachable code  }

   

结果为:

打印后打印中打印前123panic: 触发异常  goroutine 1 [running]: main.defer_call()  /Users/shuangcui/explore/panicandrecover.go:19 +0xe5 main.main()  /Users/shuangcui/explore/panicandrecover.go:6 +0x51

   

可见:

  • panic之后的defer()不会被执行
  • panic之前的defer(),按照先进后出的次序执行,最后输出panic信息

(defer机制底层,是用链表实现的一个栈)

再如:

func main() {   fmt.Println(123)   defer fmt.Println(999)   subfunc()  }  func subfunc() {   defer fmt.Println(888)   for i := 0; i > 10; i++ {  fmt.Println("当前i为:", i)  panic("have a bug")  }   defer fmt.Println(456)  }

   

结果为:

123 456 888 999

   

defer会延迟到当前函数执行 return 命令前被执行, 多个defer之间按LIFO先进后出顺序执行




情形2 (在defer内打印defer之外的主方法里操作的变量)

package main  import "fmt"  func main() {  foo() }  func foo() {  i := 0  defer func() {  //i--  fmt.Println("第一个defer", i)  }()   i++  fmt.Println("+1后的i:", i)   defer func() {  //i--  fmt.Println("第二个defer", i)  }()   i++  fmt.Println("再+1后的i:", i)   defer func() {  //i--  fmt.Println("第三个defer", i)  }()   i++  fmt.Println("再再+1后的i:", i)   i = i + 666   fmt.Println("+666后的i为:", i)  }

   

输出为:

+1后的i: 1 再+1后的i: 2 再再+1后的i: 3 +666后的i为: 669 第三个defer 669 第二个defer 669 第一个defer 669

   

情形3 (在defer内外操作同一变量)

package main  import "fmt"  func main() {  foo() }  func foo() {  i := 0  defer func() {  i--  fmt.Println("第一个defer", i)  }()   i++  fmt.Println("+1后的i:", i)   defer func() {  i--  fmt.Println("第二个defer", i)  }()   i++  fmt.Println("再+1后的i:", i)   defer func() {  i--  fmt.Println("第三个defer", i)  }()   i++  fmt.Println("再再+1后的i:", i)   i = i + 666   fmt.Println("+666后的i为:", i)  }

   

输出为:

+1后的i: 1 再+1后的i: 2 再再+1后的i: 3 +666后的i为: 669 第三个defer 668 第二个defer 667 第一个defer 666

   

情形4! (发生了参数传递!---传递参数给defer后面的函数, defer内外同时操作该参数)

package main  import "fmt"  func main() {  foo2() }  func foo2() {  i := 0  defer func(k int) {  //k--  fmt.Println("第一个defer", k)  }(i)   i++  fmt.Println("+1后的i:", i)   defer func(k int) {  //k--  fmt.Println("第二个defer", k)  }(i)   i++  fmt.Println("再+1后的i:", i)   defer func(k int) {  //k--  fmt.Println("第三个defer", k)  }(i)   i++  fmt.Println("再再+1后的i:", i)   i = i + 666   fmt.Println("+666后的i为:", i)  }

   

输出为:

+1后的i: 1 再+1后的i: 2 再再+1后的i: 3 +666后的i为: 669 第三个defer 2 第二个defer 1 第一个defer 0

   

如果取消三处k--的注释, 输出为:

+1后的i: 1 再+1后的i: 2 再再+1后的i: 3 +666后的i为: 669 第三个defer 1 第二个defer 0 第一个defer -1

   

等同于:

package main  import "fmt"  func main() {  foo3() }  func foo3() {  i := 0  defer f1(i)   i++  fmt.Println("+1后的i:", i)    defer f2(i)   i++  fmt.Println("再+1后的i:", i)   defer f3(i)  i++  fmt.Println("再再+1后的i:", i)   i = i + 666   fmt.Println("+666后的i为:", i)  }  func f1(k int) {  k--  fmt.Println("第一个defer", k) }  func f2(k int) {  k--  fmt.Println("第二个defer", k) }  func f3(k int) {  k--  fmt.Println("第三个defer", k) }

   

defer指定的函数的参数在 defer 时确定,更深层次的原因是Go语言都是值传递。


情形5! (传递指针参数!---传递参数给defer后面的函数, defer内外同时操作该参数)

package main  import "fmt"  func main() {   foo5() }  func foo5() {  i := 0  defer func(k *int) {  fmt.Println("第一个defer", *k)  }(&i)   i++  fmt.Println("+1后的i:", i)   defer func(k *int) {  fmt.Println("第二个defer", *k)  }(&i)   i++  fmt.Println("再+1后的i:", i)   defer func(k *int) {  fmt.Println("第三个defer", *k)  }(&i)   i++  fmt.Println("再再+1后的i:", i)   i = i + 666   fmt.Println("+666后的i为:", i) }

   

输出为:

+1后的i: 1 再+1后的i: 2 再再+1后的i: 3 +666后的i为: 669 第三个defer 669 第二个defer 669 第一个defer 669

   

作如下修改:

package main  import "fmt"  func main() {   foo5() }  func foo5() {  i := 0  defer func(k *int) {  (*k)--  fmt.Println("第一个defer", *k)  }(&i)   i++  fmt.Println("+1后的i:", i)   defer func(k *int) {  (*k)--  fmt.Println("第二个defer", *k)  }(&i)   i++  fmt.Println("再+1后的i:", i)   defer func(k *int) {  (*k)--  fmt.Println("第三个defer", *k)  }(&i)   i++  fmt.Println("再再+1后的i:", i)   i = i + 666   fmt.Println("+666后的i为:", i) }

   

输出为:

+1后的i: 1 再+1后的i: 2 再再+1后的i: 3 +666后的i为: 669 第三个defer 668 第二个defer 667 第一个defer 666

/template/Home/leiyu/PC/Static