當(dāng)發(fā)生像數(shù)組下標(biāo)越界或類型斷言失敗這樣的運(yùn)行錯(cuò)誤時(shí),Go 運(yùn)行時(shí)會(huì)觸發(fā)運(yùn)行時(shí) panic,伴隨著程序的崩潰拋出一個(gè) runtime.Error
接口類型的值。這個(gè)錯(cuò)誤值有個(gè) RuntimeError()
方法用于區(qū)別普通錯(cuò)誤。
panic
可以直接從代碼初始化:當(dāng)錯(cuò)誤條件(我們所測(cè)試的代碼)很嚴(yán)苛且不可恢復(fù),程序不能繼續(xù)運(yùn)行時(shí),可以使用 panic
函數(shù)產(chǎn)生一個(gè)中止程序的運(yùn)行時(shí)錯(cuò)誤。panic
接收一個(gè)做任意類型的參數(shù),通常是字符串,在程序死亡時(shí)被打印出來。Go 運(yùn)行時(shí)負(fù)責(zé)中止程序并給出調(diào)試信息。在示例 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
一個(gè)檢查程序是否被已知用戶啟動(dòng)的具體例子:
var user = os.Getenv("USER")
func check() {
if user == "" {
panic("Unknown user: no value for $USER")
}
}
可以在導(dǎo)入包的 init() 函數(shù)中檢查這些。
當(dāng)發(fā)生錯(cuò)誤必須中止程序時(shí),panic
可以用于錯(cuò)誤處理模式:
if err != nil {
panic("ERROR occurred:" + err.Error())
}
Go panicking:
在多層嵌套的函數(shù)調(diào)用中調(diào)用 panic,可以馬上中止當(dāng)前函數(shù)的執(zhí)行,所有的 defer 語句都會(huì)保證執(zhí)行并把控制權(quán)交還給接收到 panic 的函數(shù)調(diào)用者。這樣向上冒泡直到最頂層,并執(zhí)行(每層的) defer,在棧頂處程序崩潰,并在命令行中用傳給 panic 的值報(bào)告錯(cuò)誤情況:這個(gè)終止過程就是 panicking。
標(biāo)準(zhǔn)庫中有許多包含 Must
前綴的函數(shù),像 regexp.MustComplie
和 template.Must
;當(dāng)正則表達(dá)式或模板中轉(zhuǎn)入的轉(zhuǎn)換字符串導(dǎo)致錯(cuò)誤時(shí),這些函數(shù)會(huì) panic。
不能隨意地用 panic 中止程序,必須盡力補(bǔ)救錯(cuò)誤讓程序能繼續(xù)執(zhí)行。