當發(fā)生像數組下標越界或類型斷言失敗這樣的運行錯誤時,Go 運行時會觸發(fā)運行時 panic,伴隨著程序的崩潰拋出一個 runtime.Error 接口類型的值。這個錯誤值有個 RuntimeError() 方法用于區(qū)別普通錯誤。
panic 可以直接從代碼初始化:當錯誤條件(我們所測試的代碼)很嚴苛且不可恢復,程序不能繼續(xù)運行時,可以使用 panic 函數產生一個中止程序的運行時錯誤。panic 接收一個做任意類型的參數,通常是字符串,在程序死亡時被打印出來。Go 運行時負責中止程序并給出調試信息。在示例 13.2 panic.go 中闡明了它的工作方式:
package main
import "fmt"
func main() {
fmt.Println("Starting the program")
panic("A severe error occurred: stopping the program!")
fmt.Println("Ending the program")
}
輸出如下:
Starting the program
panic: A severe error occurred: stopping the program!
panic PC=0x4f3038
runtime.panic+0x99 /go/src/pkg/runtime/proc.c:1032
runtime.panic(0x442938, 0x4f08e8)
main.main+0xa5 E:/Go/GoBoek/code examples/chapter 13/panic.go:8
main.main()
runtime.mainstart+0xf 386/asm.s:84
runtime.mainstart()
runtime.goexit /go/src/pkg/runtime/proc.c:148
runtime.goexit()
---- Error run E:/Go/GoBoek/code examples/chapter 13/panic.exe with code Crashed
---- Program exited with code -1073741783
一個檢查程序是否被已知用戶啟動的具體例子:
var user = os.Getenv("USER")
func check() {
if user == "" {
panic("Unknown user: no value for $USER")
}
}
可以在導入包的 init() 函數中檢查這些。
當發(fā)生錯誤必須中止程序時,panic 可以用于錯誤處理模式:
if err != nil {
panic("ERROR occurred:" + err.Error())
}
Go panicking:
在多層嵌套的函數調用中調用 panic,可以馬上中止當前函數的執(zhí)行,所有的 defer 語句都會保證執(zhí)行并把控制權交還給接收到 panic 的函數調用者。這樣向上冒泡直到最頂層,并執(zhí)行(每層的) defer,在棧頂處程序崩潰,并在命令行中用傳給 panic 的值報告錯誤情況:這個終止過程就是 panicking。
標準庫中有許多包含 Must 前綴的函數,像 regexp.MustComplie 和 template.Must;當正則表達式或模板中轉入的轉換字符串導致錯誤時,這些函數會 panic。
不能隨意地用 panic 中止程序,必須盡力補救錯誤讓程序能繼續(xù)執(zhí)行。