Go语言panic()和recover()的用法(非常详细)
在 Go 语言中,程序在编译时可能捕获到一些错误。有些错误只能在运行时出现,例如数组访问越界、空指针引用等,这些运行时出现的错误都会引起宕机(panic)。
当宕机发生时,程序停止运行,编译器输出对应的报错信息。如果在宕机后想让程序继续执行,则可以使用宕机恢复(recover)机制。
panic() 函数的语法格式如下:
在手动触发宕机时,堆栈和 goroutine 信息将输出到控制台,所以通过宕机也可以方便地查找发生错误的位置,有利于及时排查和解决问题。
代码如下:
代码如下:
在触发 panic 后执行的 defer 语句内还可以继续触发 panic,进一步抛出异常,直到程序整体崩溃。
如果当前执行的函数发生 panic,那么调用 recover() 函数可以获取 panic 信息,并且恢复程序正常执行。
示例代码如下:
如果 panic() 函数和 recover() 函数一起使用,并且程序中的函数调用比较复杂,则在执行完对应的 defer 语句后,程序退出当前函数并返回到调用处继续执行。代码如下:
当宕机发生时,程序停止运行,编译器输出对应的报错信息。如果在宕机后想让程序继续执行,则可以使用宕机恢复(recover)机制。
Go语言panic()宕机
panic() 是 Go语言的内置函数。它类似于其他编程语言中抛出异常的 throw 语句。panic() 一般用在函数内部。panic() 函数的语法格式如下:
func panic(v interface{})
panic() 函数的参数可以是任意类型的值。1) 手动触发宕机
在程序中可以手动触发宕机使程序崩溃,这样可以使开发者及时发现错误,减少可能的损失。在手动触发宕机时,堆栈和 goroutine 信息将输出到控制台,所以通过宕机也可以方便地查找发生错误的位置,有利于及时排查和解决问题。
代码如下:
package main
func main() {
panic("Program crash")
}
运行结果如下:
panic: Program crash
goroutine 1 [running]:
main.main()
e:/Code/10/demo.go:4 +0x27
exit status 2
2) 宕机时触发defer语句
当调用函数执行到 panic() 时,不执行 panic() 后面的代码,如果在 panic() 函数前面有 defer 语句则正常执行该语句,之后返回调用函数,执行每一层的 defer 语句,直到所有正在执行的函数都被终止为止。代码如下:
package main
import "fmt"
func test() {
defer func() {
fmt.Println("exit func test")
}()
panic("Program crash") // 触发宕机
}
func main() {
defer func() {
fmt.Println("exit func main")
}()
test() // 运行代码不会执行
fmt.Println("不会执行")
}
运行结果如下:
exit func test
exit func main
panic: Program crash
goroutine 1 [running]:
main.main()
e:/Code/10/demo.go:9 +0x49
main.test()
e:/Code/10/demo.go:15 +0x3f
exit status 2
- 执行 test() 函数中的 panic 触发宕机;
- 宕机前,优先执行 defer 语句。由于test()函数内的匿名函数通过 defer 语句延迟执行,因此在触发宕机后,执行 test() 函数中的匿名函数,打印“exit func test”;
- 由于主函数内的匿名函数通过 defer 语句延迟执行,因此在主函数退出前将执行其中的匿名函数,打印“exit func main”;
- 打印抛出的 panic 并退出程序。
在触发 panic 后执行的 defer 语句内还可以继续触发 panic,进一步抛出异常,直到程序整体崩溃。
Go语言recover()宕机恢复
Go语言中,使用 recover() 可以在宕机后让程序继续执行。recover() 是 Go语言的内置函数,该函数可以捕获 panic 信息,类似于其他编程语言中用于捕获异常的 try…catch 语句。recover 通常在使用 defer 语句的函数中执行。如果当前执行的函数发生 panic,那么调用 recover() 函数可以获取 panic 信息,并且恢复程序正常执行。
示例代码如下:
package main
import "fmt"
func test() {
defer func() {
err := recover()
if err != nil {
fmt.Println(err)
}
fmt.Println("恢复执行")
}()
panic("程序崩溃") // 触发宕机
}
func main() {
fmt.Println("程序开始")
test()
fmt.Println("程序结束")
}
运行结果如下:
程序开始
程序崩溃
恢复执行
程序结束
如果 panic() 函数和 recover() 函数一起使用,并且程序中的函数调用比较复杂,则在执行完对应的 defer 语句后,程序退出当前函数并返回到调用处继续执行。代码如下:
package main
import "fmt"
func first() {
fmt.Println("first 函数开始")
second()
fmt.Println("first 函数结束")
}
func second() {
defer func() { recover() }()
fmt.Println("second 函数开始")
third()
fmt.Println("second 函数结束")
}
func third() {
fmt.Println("third 函数开始")
panic("Program crash") // 触发宕机
fmt.Println("third 函数结束")
}
func main() {
fmt.Println("程序开始")
first()
fmt.Println(19)
fmt.Println("程序结束")
}
运行结果为:
程序开始
first 函数开始
second 19开始
Program crash
second 函数结束
first 函数结束
程序结束
如果 defer 语句中也存在 panic,那么只有最后一个 panic 可以被 recover() 函数捕获。代码如下:注意,虽然 panic() 函数和 recover() 函数可以模拟其他语言的异常机制,但在编写普通函数时不建议使用这种特性。
package main
import "fmt"
func main() {
defer func() {
err := recover()
if err != nil {
fmt.Println(err)
}
fmt.Println("恢复执行")
}()
defer func() {
panic("defer panic") // 触发宕机
}()
panic("panic") // 触发宕机
}
运行结果如下:
defer panic
恢复执行
ICP备案:
公安联网备案: