recover和panic的使用注意事项

panic & recover 作用范围的:

  • recover 只有在 defer 中调用才会生效;
  • panic 允许在 defer 中嵌套多次调用;
  • panic 只会对当前 Goroutine 的 defer 有效

恢复异常代码

defer func() {
  if err := recover(); err !=nil{
   fmt.Println(err)
  }
 }()

runtime 中有哪些坑?

panic 我们在实现业务的时候是不推荐使用的,但是并不代表 runtime 里面不会用到,对于不了解 Go 底层实现的新人来说,这无疑是挖了一堆深坑。如果不熟悉这些坑,是不可能写出健壮的 Go 代码。

下面我将 runtime 中的异常分一下类,有一些异常是 recover 也捕获不到的,有一些是正常的 panic 可以被捕获到。

无法捕获的异常

内存溢出

func main() {
 defer errorHandler()
 _ = make([]int64, 1<<40)
 fmt.Println("can recover")
}

func errorHandler() {
 if r := recover(); r != nil {
  fmt.Println(r)
 }
}

map 并发读写

func main() {
 defer errorHandler()
 m := map[string]int{}

 go func() {
  for {
   m["x"] = 1
  }
 }()
 for {
  _ = m["x"]
 }
}

func errorHandler() {
 if r := recover(); r != nil {
  fmt.Println(r)
 }
}

能够被捕获的异常

数组 ( slice ) 下标越界

func foo(){
 defer func() {
  if r := recover(); r != nil {
   fmt.Println(r)
  }
 }()
 var bar = []int{1}
 fmt.Println(bar[1])
}

func main(){ 
 foo()
 fmt.Println("exit")
}

空指针异常

func foo(){
 defer func() {
  if r := recover(); r != nil {
   fmt.Println(r)
  }
 }()
 var bar *int
 fmt.Println(*bar)
}

func main(){
 foo()
 fmt.Println("exit")
}

 

posted @ 2022-10-08 10:16  国泰君安  阅读(121)  评论(0)    收藏  举报