Golang 中的恢复


2022年1月23日, Learn eTutorial
2021

在本教程中,您将了解Go语言中的恢复(recover)和恐慌(panic)。在开始本教程之前,请确保您了解我们在上一个教程中讨论过的panic概念。

Go语言中的recover是什么?

recover函数是Go编程语言中用于从panic情况中恢复的内置函数。因此,即使Go程序中发生panic,它也能够从该panic中恢复并继续正常执行。这就是recover关键字的意义所在。
让我们通过下面的panic程序开始学习


package main
import "fmt"

func main() {
 fmt.Println("lets learn about recover() in golang")
 Panicfunc()
 fmt.Println("learned all about recover() ")
}
func Panicfunc() {
 fmt.Println("instruction just before panicking situation")
 panic("Panicfunc terminates from execution")
 fmt.Println("instruction after panic does not execute")
}

输出


lets learn about recover() in golang
instruction just before paniciking situation
panic: Panicfunc terminates from execution

goroutine 1 [running]:
main.Panicfunc()
 /tmp/sandbox1636989584/prog.go:13 +0x65
main.main()
 /tmp/sandbox1636989584/prog.go:7 +0x5b

Program exited.

一个panic函数是Go语言中的一个异常,程序会终止其正常执行,因为它不知道接下来该做什么,并留下一个错误消息,这个消息要么是程序员使用内置的panic函数作为参数传入的,要么是运行时默认生成的。
给定的程序由两个函数组成,一个是main(),另一个是Panicfunc()
当程序从主函数开始执行时,它会执行第一条指令以打印“让我们了解Go语言中的recover()”。

fmt.Println("让我们了解Go语言中的recover()")

主函数扫描下一条要执行的指令,这是一个名为Panicfunc()的函数。控制权切换到Panicfunc(),在那里执行一组指令。下面给出的第一条指令被执行并打印
在发生panic情况之前的指令。
fmt.Println("在panic情况之前的指令")

panic("Panicfunc终止执行")

当程序遇到panic函数时,它会终止执行下面的指令,并打印该字符串,即panic: Panicfunc终止执行,并留下一些堆栈跟踪。

如何在panic程序中使用recover函数?

让我们继续使用上面讨论的相同代码,但添加了一些新代码。
在上面的代码中添加了一个名为Panicrecover的新函数,其中使用了预定义的recover()函数。


func Panicrecover() {
 if err := recover(); err != nil {
  fmt.Println("Recovered from panic \n", err)
 }

为了恢复正常的执行流程,我们需要在Panicfunc ()中添加defer函数。
要理解defer的意义,请参考我们已经介绍过的教程。Recover在延迟函数中很有用。因此,如果您想在panic函数中(即在我们的示例Panicfunc中)使用Panicrecover函数(recover ()),您需要调用defer函数,它表示

defer Panicrecover()

让我们回顾一下defer的概念。
任何被延迟调用的函数都称为延迟函数,它们在封闭函数之前被调用。在我们的程序中,上面给出的代码将延迟recover函数。

在这个程序中,当发生panic时,Panicfunc通过调用Panicrecover函数来恢复。在Panicrecover函数内部,我们调用了内置的recover(),它允许程序正常执行。执行从main()调用的Panicfunc()函数处恢复。
 让我们检查完整的代码 


package main
import "fmt"

func main() {
 fmt.Println("lets learn about recover() in golang")
 Panicfunc()
 fmt.Println("learned all about recover() ")
}

func Panicfunc() {
 defer Panicrecover()
 fmt.Println("instruction just before panicking situation")
 panic("Panicfunc  resume  execution")
 fmt.Println("instruction after panic does not execute")

}
func Panicrecover() {
 if err := recover(); err != nil {
  fmt.Println("Recovered from panic \n", err)
 }
}

输出


lets learn about recover() in golang
instruction just before panicking situation
Recovered from panic 
Panicfunc  resume  execution
learned all about recover() 

Program exited.

程序中的控制流

GO : Recover

让我们总结一下上面给出的流程图

  •   程序从main函数开始执行,打印第一条语句:让我们了解Go语言中的recover()
  •   然后Panicfunc()运行,它延迟了一个函数Panicrecover()。
  •   Panicfunc打印在发生panic情况之前的指令
  •   然后函数开始panic,但在此之前它会执行延迟函数。
  •   延迟函数调用recover ()函数
  •   由于这是panic情况的上下文,如果错误不等于nil,则检查返回类型并打印“从panic中恢复,并继续带有panic返回的消息”。
  •   执行返回到main函数并打印“已了解所有关于recover()的内容” 
  •   这是recover函数用于克服panic情况的程序。

recover函数是否返回nil值?

是的,recover函数在正常执行期间返回nil值。
考虑上面讨论的相同代码,但省略了panic情况。只需删除 

panic("Panicfunc  resume  execution")

代码如下所示


package main
import "fmt"

func main() {
 fmt.Println("lets learn about recover() in golang")
 Panicfunc()
 fmt.Println("learned all about recover() ")
}

func Panicfunc() {
 defer Panicrecover()
 fmt.Println("instruction just before panicking situation")

 fmt.Println("instruction after panic does not execute")

}
func Panicrecover() {
 if err := recover(); err != nil {
  fmt.Println("Recovered from panic \n", err)
 }

}

输出


lets learn about recover() in golang
instruction just before panicking situation
instruction after panic does not execute
learned all about recover() 

Program exited.

在上面的程序中,控制流正常。recover函数没有什么可恢复的,没有panic情况,所以它返回一个nil值。
更好地理解下面带有recover函数(包含else部分,说明recover函数返回nil值)的程序。


package main
import "fmt"

func main() {
 fmt.Println("lets learn about recover() in golang")
 Panicfunc()
 fmt.Println("learned all about recover() ")
}

func Panicfunc() {
 defer Panicrecover()
 fmt.Println("instruction just before paniciking situation")

 fmt.Println("instruction after panic does not execute")

}
func Panicrecover() {
 if err := recover(); err != nil {
  fmt.Println("Recovered from panic \n", err)
 } else {
  fmt.Println("Recover a nil value :", err)
 }

}

输出


lets learn about recover() in golang
instruction just before paniciking situation
instruction after panic does not execute
Recover a nil value : 
learned all about recover() 

Program exited.

注意

  • Recover仅在defer函数中使用。
  • 在正常执行期间调用recover会返回nil值。
  • 对panic程序调用recover会通过识别panic语句来恢复其正常执行。