Go异常处理机制panic和recover

简介: Go异常处理机制panic和recover

recover


使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层,直至程序crash。但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。

func main() {
  print(123)
  print(456)
  panic("throw an error")
  print(678) //IDE会有提示: Unreachable code
}

结果:

123456panic: throw an error
goroutine 1 [running]:
main.main()
    /Users/shuangcui/explore/panicandrecover.go:31 +0x67

使用recover()捕获异常:

func main() {
  print(123)
  defer func() {
    if err := recover(); err != nil {
      print("recover it")
    }
  }()
  print(456)
  panic("throw an error")
  print(678) //IDE会有提示: Unreachable code
}

结果为:

123456recover it

如果有两个recover,则捕获异常的是后一个

func main() {
  print(123)
  defer func() {
    if err := recover(); err != nil {
      print("recover it")
    }
  }()
  defer func() {
    if err := recover(); err != nil {
      print("复原!")
    }
  }()
  print(456)
  panic("throw an error")
  print(678) //IDE会有提示: Unreachable code
}

结果为:

123456复原!

panic之后的任何代码都不会继续执行


前提是panic不在if里面

package main
import "fmt"
func main() {
  defer_call()
  fmt.Println("333 Helloworld")
}
func defer_call() {
  defer func() {
    fmt.Println("11111")
  }()
  defer func() {
    fmt.Println("22222")
  }()
  defer func() {
    if r := recover(); r != nil {
      fmt.Println("Recover from r : ", r)
    }
  }()
  defer func() {
    fmt.Println("33333")
  }()
  fmt.Println("111 Helloworld")
  panic("Panic 1!")
    //使用panic抛出异常后, 将立即停止当前函数的执行并运行所有被defer的函数,然后将panic抛向上一层, 直至程序crash
    //但是也可以使用被defer的recover函数来捕获异常阻止程序的崩溃,recover只有被defer后才是有意义的。
  panic("Panic 2!") //panic1之后的panic2没有任何机会会被执行, panic2之后的任何代码更没有任何机会被执行
  fmt.Println("222 Helloworld")
}

输出为:

111 Helloworld
33333
Recover from r :  Panic 1!
22222
11111
333 Helloworld

对于goroutine中的panic,协程外面的recover是无法恢复的,goroutine中的recover,同样无法恢复协程外的panic

微信截图_20230626183345.png

但协程中的recover可以恢复协程中的panic

package main
import (
  "fmt"
  "time"
)
func main() {
  go func() {
    defer func() {
      if err := recover(); err != nil {
        fmt.Println("recover err:", err)
      }
    }()
    panic("里面出错了")
  }()
  //panic("外面出错了")
  time.Sleep(1 * time.Second)
}

输出为:

recover err 里面出错了


主方法中的recover,也可以恢复子方法里的panic


但如果go subfunc(),则同样无法捕获subfunc中的异常

func main() {
  fmt.Println(123)
  defer fmt.Println(999)
  defer func() {
    if err := recover(); err != nil {
      fmt.Println("恢复异常:",err)
    }
  }()
  subfunc()
}
func subfunc() {
  defer fmt.Println(888)
  panic("出现了bug")
  defer fmt.Println(456)
}

结果为:

123
888
恢复异常: 出现了bug
999

因为panic发生的时候,panic函数后面的语句都不会执行了,所以recover函数不能放在panic语句后面执行,而要放在defer函数中执行。

使用 panic 抛出异常后,函数执行将从调用 panic 的地方停止,如果函数内有 defer 调用,则执行 defer 后边的函数调用,如果 defer 调用的函数中没有捕获异常信息,这个异常会沿着函数调用栈往上传递,直到 main 函数仍然没有捕获异常,将会导致程序异常退出


如何区别使用 panic 和 error 两种方式?

惯例是:导致关键流程出现不可修复性错误的使用 panic ,其他使用 error 。

panic 和 recover 的组合有如下特性:

  • 有 panic 没 recover ,程序宕机。
  • 有 panic 也有 recover ,程序不会宕机,执行完对应的 defer 后,从宕机点退出当前函数后继续执行。


目录
相关文章
|
Go
Go异常处理机制panic和recover
Go异常处理机制panic和recover
131 0
|
10月前
|
网络协议 BI Go
Go-异常处理(defer recover panic)
Go-异常处理(defer recover panic)
93 0
|
Go
Go 专栏|错误处理:defer,panic 和 recover
Go 专栏|错误处理:defer,panic 和 recover
315 0
Go 专栏|错误处理:defer,panic 和 recover
|
Go 索引
Go panic & recover 使用注意点:
Go panic & recover 使用注意点:
460 0
Go语言,panic和recover 遇到错误继续处理
Go语言,panic和recover 遇到错误继续处理
174 0
|
编译器 Go
Go学习笔记-defer、panic、recover分析
Go学习笔记-defer、panic、recover分析
104 1
Go学习笔记-defer、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
【Go】panic、recover 区分
【Go】panic、recover 区分
104 0
|
10月前
|
Go
Go语言中的异常处理:理解panic与recover
【2月更文挑战第7天】Go语言虽然以简洁和直接错误处理机制而著称,但它也提供了`panic`和`recover`这两个内置函数来处理程序中的异常情况。本文将深入探讨Go语言中的异常处理机制,包括`panic`和`recover`的使用场景、原理以及最佳实践,帮助读者更好地理解如何在Go中处理异常情况。