panic
数组越界, 空指针引用等, 这些运行时错误会引起 panic
异常
:::info
我们不应该通过调用 panic
函数来报告普通错误, 而应该只把他作为报告致命错误的一种方式.
:::
当某些不应该发生的场景发生时, 我们就应该调用 panic
一般而言, 当 panic 异常发生时, 程序会中断运行, 并立即执行在该 goroutine(一种线程在中被延迟的函数 (defer 机制)). 随后, 程序崩溃并输出日志信息. 日志信息包括 panic value 和函数调用的堆栈跟踪信息
不是所有的 panic 异常都来自运行时, 直接调用内置的 panic 函数也会引发 panic 异常, panic 函数接收任何值作为参数
func panic(v interface{})
虽然Go语言的 panic 机制类似于其他语言的异常,但 panic 的适用场景有一些不同,由于 panic 会引起程序的崩溃,因此 panic 一般用于严重错误,如程序内部的逻辑不一致。任何崩溃都表明了我们的代码中可能存在漏洞,所以对于大部分漏洞,我们应该使用Go语言提供的错误机制,而不是 panic。
手动触发宕机
Go
语言可以在程序中手动触发宕机,让程序崩溃,这样开发者可以及时地发现错误,同时减少可能的损失。
Go
语言程序在宕机时,会将堆栈和 goroutine
信息输出到控制台,所以宕机也可以方便地知晓发生错误的位置,那么我们要如何触发宕机呢,示例代码如下所示:
package main
func main() {
panic("crash")
}
代码运行崩溃并输出如下:
panic: crash
goroutine 1 [running]:
main.main()
D:/code/main.go:4 +0x40
exit status 2
以上代码中只用了一个内建的函数 panic()
就可以造成崩溃,panic()
的声明如下:
func panic(v interface{}) //panic() 的参数可以是任意类型的。
在宕机时触发延迟执行语句
当 panic()
触发的宕机发生时,panic()
后面的代码将不会被运行,但是在 panic()
函数前面已经运行过的 defer
语句依然会在宕机发生时发生作用,参考下面代码:
package main
import "fmt"
func main() {
defer fmt.Println("宕机后要做的事情1")
defer fmt.Println("宕机后要做的事情2")
panic("宕机")
}
代码输出如下:
宕机后要做的事情 2
宕机后要做的事情 1
panic: 宕机
goroutine 1 [running]:
main.main()
D:/code/main.go:8 +0xf8
exit status 2
对代码的说明:
- 第 6 行和第 7 行使用 defer 语句延迟了 2 个语句。
- 第 8 行发生宕机。
宕机前,defer 语句会被优先执行,由于第 7 行的 defer 后执行,因此会在宕机前,这个 defer 会优先处理,随后才是第 6 行的 defer 对应的语句,这个特性可以用来在宕机发生前进行宕机信息处理。