我们可以调用内置函数panic来产生一个恐慌以使当前协程进入恐慌状况。进入恐慌状况是另一种使当前函数调用开始返回的途径。一旦一个函数调用产生一个恐慌,此函数调用将立即进入它的退出阶段。通过在一个延迟函数调用之中调用内置函数recover,当前协程中的一个恐慌可以被消除,从而使得当前协程重新进入正常状况。如果一个协程在恐慌状况下退出,它将使整个程序崩溃。
func panic(v interface{})
func recover() interface{}

func main() {
    defer func() {
        fmt.Println("正常退出")
    }()
    fmt.Println("嗨!")
    defer func() {
        v := recover()
        fmt.Println("恐慌被恢复了:", v)
    }()
    // 产生一个恐慌,进入退出阶段
    panic("拜拜!") 
    fmt.Println("执行不到这里")
}

//输出:
//嗨! 
//恐慌被恢复了: 拜拜!
//正常退出

一个函数调用最多只能和一个未恢复的恐慌相关联。 如果一个调用正和一个未恢复的恐慌相关联,则

  • 在此恐慌被恢复之后,此调用将不再和任何恐慌相关联。
  • 当在此函数调用中产生了一个新的恐慌,此新恐慌将替换原来的未被恢复的恐慌做为和此函数调用相关联的恐慌。

    func main() {
      defer func() {
          fmt.Println(recover()) // 3
      }()
      
      defer panic(3) // 将替换恐慌2
      defer panic(2) // 将替换恐慌1
      defer panic(1) // 将替换恐慌0
      panic(0)
    }

    Go白皮书中提到:
    在下面的情况下,recover函数调用的返回值为nil

  • 当前协程并没有处于恐慌状态;
  • recover函数并未直接在一个延迟函数调用中调用。

panic参数为nil时:

func main() {
    defer func() {
        v := recover()
        fmt.Println(v)
    }()
    defer func() {
        fmt.Println("正常退出")
    }()
    panic(nil)
}
//1.19.4
//正常退出
//<nil>

//1.23.0
//正常退出
//panic called with nil argument

defer相关笔记可查看


桃瑾
1 声望1 粉丝

常常播种,有时收获


« 上一篇
go-defer
下一篇 »
限流算法