Golang中的defer(1)

简介: Golang中的defer(1)

面试常问之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
目录
相关文章
|
3月前
|
Go Python
通过 atexit 模块让 Python 实现 Golang 的 defer 功能
通过 atexit 模块让 Python 实现 Golang 的 defer 功能
33 2
|
5月前
|
Serverless Go
Golang 开发函数计算问题之defer 中的 recover() 没有捕获到 如何解决
Golang 开发函数计算问题之defer 中的 recover() 没有捕获到 如何解决
|
5月前
|
人工智能 数据库连接 Go
golang defer 详解
golang defer 详解
54 0
|
8月前
|
Go 开发者
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
176 2
|
安全 Go
Golang 语言中的 defer 怎么使用?
Golang 语言中的 defer 怎么使用?
54 0
|
8月前
|
Java Go
浅谈Golang 不同版本的defer
浅谈Golang 不同版本的defer
63 1
|
8月前
|
存储 编译器 测试技术
Golang底层原理剖析之defer
Golang底层原理剖析之defer
85 0
|
存储 Java 编译器
Golang中的defer(2)
Golang中的defer(2)
4728 2
|
编译器 Go
Golang中的defer
Golang中的defer
67 0