GO 中的 defer 有哪些注意事项?下

简介: GO 中的 defer 有哪些注意事项?下

上次一起写了 3 个案例,咱们这一次继续,这一次的会比上一次的稍微不太一样

案例 1

还有一个也非常常用的案例,使用 defer 来捕获异常 ,也就是当程序崩溃的时候,defer 语句可以帮我们兜底,可以捕获异常后按照我们期望的逻辑进行执行,让程序回到正确的轨道上面

  • 一般使程序崩溃很简单, C/C++ 的时候,我们可以造异常,例如除 0 ,或者是数组越界等等就会导致程序崩溃
  • GO 里面造异常也可以按照上面这种方式,但是我们也可以使用 panic 函数来实现程序崩溃
  • 写一个简单的例子,把自己的程序搞崩
func testDefer() {
  defer func() {
    fmt.Println(" panic 前 ")
  }()
  panic("i panic") 
  defer func() {
    fmt.Println(" panic 后")
  }()
}
func main() {
  testDefer()
  fmt.Println("program over")
}

其实我们看 goland 工具就可以看到,下面这一句话是不会被执行的

defer func() { fmt.Println(" panic 后") }()

实际运行程序后,结果如下:

我们可以看到实际效果,程序是崩溃了,因为 fmt.Println("program over") 没有打印出来,且看图片,是有具体的 panic 信息的

从上述可以看明白, panic 之后的程序是不会执行的, panic 之前的 defer 语句会执行,因为他先入栈了

那么我们来捕获一下异常

还是上面的代码,我们来捕获一下异常,就是加一句话就可以了

func testDefer() {
  defer func() {
    fmt.Println(" panic 前 ")
    if err := recover(); err != nil {
      fmt.Println(" xdm , 我捕获到异常了,程序不用崩溃了 ")
    }
  }()
  panic("i panic") //触发defer出栈
  defer func() {
    fmt.Println(" panic 后")
  }()
}
func main() {
  testDefer()
  fmt.Println("program over")
}

看上述代码,panic 之后的程序仍然是不会执行的,但是我们加入了 recover() 语句, 他会帮助我们捕获异常,处理异常

执行上述代码后,效果如下:

> go run main.go
 panic 前
 xdm , 我捕获到异常了,程序不用崩溃了
program over

根据打印我们可以看出,结论和上面一个例子结论一致,并且加入异常捕获之后,程序的崩溃堆栈信息是不会打印出来了, 并且程序是正常退出了,我们可以看到正常打印了 program over

案例 2

咱们再来字后一个 案例 玩一下

上面都是出现 1 个 panic 的情况 ,那么,如果是出现多个 panic 是怎么玩的呢, defer 他还能捕获到 panic 信息吗?若出现 2 个 panic, defer 也能捕获 2 个吗?

func main() {
  defer func() {
    if err := recover(); err != nil {
      fmt.Println("xdm, 我捕获到异常了")
    }
  }()
  defer func() {
    panic("defer func  panic")
  }()
  panic(" i panic")
  panic(" last  panic")
  fmt.Println("baibai")
}

看到上述代码,一时间知道怎么走,但是我们看 goland 就知道 panic 后面的语句肯定不会执行

尝试分析一下,前面有说,defer 是按照栈的顺序来的

  • 第 1 个 derfer 先入栈
  • 第 2 个 defer 后入栈
  • 执行 panic 程序崩溃 应该会报错 i panic
  • 但是程序退出的时候,会出栈,会先执行 第 2 个 defer , 这个 defer 也是一个 panic, 则会覆盖刚才的 panic 信息,应该会报错 defer func panic
  • 执行出栈,执行到第 1 个 defer ,异常被捕获了,程序正常退出,因此执行程序会有如下结果
xdm, 我捕获到异常了

好了,今天就到这里,感兴趣的朋友也可以玩起来

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

相关文章
|
1月前
|
Go
Go语言中defer的执行顺序详解
【2月更文挑战第22天】
28 4
|
5月前
|
Cloud Native Go
GO 中的 defer 有哪些注意事项?上
GO 中的 defer 有哪些注意事项?上
|
6月前
|
Go
Go语言编程的一大杀器!详解defer语句
Go语言编程的一大杀器!详解defer语句
29 0
|
5天前
|
Go 开发者
Golang深入浅出之-Go语言 defer、panic、recover:异常处理机制
Go语言中的`defer`、`panic`和`recover`提供了一套独特的异常处理方式。`defer`用于延迟函数调用,在返回前执行,常用于资源释放。它遵循后进先出原则。`panic`触发运行时错误,中断函数执行,直到遇到`recover`或程序结束。`recover`在`defer`中捕获`panic`,恢复程序执行。注意避免滥用`defer`影响性能,不应对可处理错误随意使用`panic`,且`recover`不能跨goroutine捕获panic。理解并恰当使用这些机制能提高代码健壮性和稳定性。
16 2
|
27天前
|
存储 缓存 安全
掌握Go语言:Go语言Map,高效键值对集合的应用与注意事项详解(26)
掌握Go语言:Go语言Map,高效键值对集合的应用与注意事项详解(26)
|
3月前
|
网络协议 BI Go
Go-异常处理(defer recover panic)
Go-异常处理(defer recover panic)
31 0
|
4月前
|
存储 Go
Go 语言之 Maps 详解:创建、遍历、操作和注意事项
Maps用于以键值对的形式存储数据值。Maps中的每个元素都是一个键值对。Maps是一个无序且可更改的集合,不允许重复。Maps的长度是其元素的数量。您可以使用 len() 函数来查找长度。Maps的默认值是 nil。Maps保存对底层哈希表的引用。
42 0
|
4月前
|
Go
go defer用法_类似与python_java_finially
go defer用法_类似与python_java_finially
36 0
|
5月前
|
存储 Java 编译器
GO 中 defer的实现原理
GO 中 defer的实现原理