likes
comments
collection
share

Go 编程 | 连载 26 - Go 的 panic 与 recover

作者站长头像
站长
· 阅读数 36

一、panic 和 recover

Go 语言中的错误处理机制是如果一个可能造成错误的函数,需要在该函数的返回值中增加一个错误接口。如果函数调用成功,错误接口将被返回 nil,如果调用失败,则返回具体的错误内容。

在函数调用后需要检查错误,进行必要的错误处理。

Go 编程 | 连载 19 - 接口的应用 讲到了实例化错误类型的多种方式,这里不再赘述。

panic

panic 在 Go 语言中表示是宕机,既服务停止或者程序终止运行。

Go 语言中可以手动触发 panic,让程序终止运行,这样可以在程序发生错误时及时止损。panic 发生时会将堆栈和 goroutine 信息输出到控制台,可以据此知晓发生错误的位置,如果在编译时加入的调试信息甚至连 panic 发生时的变量运行状态都可以获得。

func main() {
   
   var info any
   info = "crash"
   panic(info)
   
   fmt.Println("Hello Go")

}

执行上述代码,输出结果如下:

panic: crash

goroutine 1 [running]:
main.main()
	/ex25.go:6 +0x27

只通过一个 panic 函数就是程序终止运行,panic 函数后面的代码也没有执行。panic 函数是 Go 的内置函数,该函数的参数是一个 any 类型,而 any 是一个接口。

当 panic 发生时,panic 函数后的代码将不会被执行,但是 panic 函数前面已经运行过的 defer 语句仍然会在 panic 发生时运行。

func main() {

   defer fmt.Println("panic 前")
   var info any
   info = "crash"
   panic(info)

   fmt.Println("Hello Go")
   defer fmt.Println("panic 后")
}

执行上述代码,输出结果如下:

panic 前
panic: crash

goroutine 1 [running]:
main.main()
	/ex25.go:10 +0x73

panic 发生前,在 panic 函数前面的 defer 会优先执行,但是在 panic 函数后的 defer 不会被执行,因为 panic 发生程序停止服务,包括 defer 语句所有的代码都不会被执行。

recover

代码运行时的发生的错误可以通过 deferrecover 实现错误捕捉和恢复。让代码发生在泵阔后允许继续运行,类似其他语言中的 try-catch

Go 中没有异常的概念,只有错误,panic 函数触发宕机就类似于其他语言中的异常。

recover 函数的返回值为任意内容

func recover() any
package main

//noinspection ALL
import (
   "fmt"
   "runtime"
)

type panicContent struct {
   function string
}

//noinspection ALL
func main() {

   fmt.Println("手动触发 painc 前")

   samFun(func() {
      panic(&panicContent{
         "手动触发 panic",
      })
   })

   fmt.Println("手动触发 painc 后")

   fmt.Println("空指针导致 panic")

   samFun(func() {
      fmt.Println("赋值前")

      var a *int
      *a = 1

      fmt.Println("赋值后")
   })

   fmt.Println("panic 后")
}

func samFun(f func()) {

   defer func() {
      // 发生 panic 时,获取 panic 函数传递的上下文并打印
      err := any(recover())

      switch err.(type) {
      case runtime.Error:
         fmt.Println("runtime error:", err)
      default:
         fmt.Println("error:",err)
      }

   }()

   f()
}

执行上述代码,输出结果如下:

手动触发 painc 前
error: &{手动触发 panic}
手动触发 painc 后
空指针导致 panic
赋值前
runtime error: runtime error: invalid memory address or nil pointer dereference
panic 发生后

panic 函数和 recover 函数同时存在,程序不会宕机,执行对应的 defer 语句后,从宕机点退出当前函数后继续执行。

二、panic 和 recover 的坑

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 中错误与异常的区分

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

go 中的 ”try catch“ 这默写

Go 编程 | 连载 26 - Go 的 panic 与 recover

这默写是不行的

Go 编程 | 连载 26 - Go 的 panic 与 recover

panic 中的坑

先写一个 http server

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover 出现异常,服务未停

开启一个协程,在携程中抛出异常 Go 编程 | 连载 26 - Go 的 panic 与 recover 出现异常,服务停止

Go 编程 | 连载 26 - Go 的 panic 与 recover

为什么在主线程中 panic 不会报错导致服务停止,在携程中 panic 就会导致服务停止

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

在当前携程中捕获异常,防止出现报错

Go 编程 | 连载 26 - Go 的 panic 与 recover

Go 编程 | 连载 26 - Go 的 panic 与 recover

转载自:https://juejin.cn/post/7134267437796573220
评论
请登录