做者:Stefan Nilssonhtml
原文網址:yourbasic.org/golang/reco…git
Panics 相似於 C++ 和 Java 異常,但僅適用於運行時錯誤,例如跟隨一個 nil 指針或試圖對數組訪問超出範圍的索引。爲了表示諸如文件結束之類的事件,Go 程序使用內置 error
類型。有關錯誤的更多信息,請參見 錯誤處理最佳實踐 和 3種建立錯誤的簡單方法。github
Panic 中止 goroutine 的正常執行golang
panic 是由運行時錯誤或對內置函數 panic
的顯式調用引發的。編程
堆棧跟蹤記錄 —— 全部活動堆棧幀的報告 —— 一般在 panic 發生時將其打印到控制檯。堆棧跟蹤對於調試很是有用:數組
這是一個堆棧跟蹤的示例:bash
goroutine 11 [running]:
testing.tRunner.func1(0xc420092690)
/usr/local/go/src/testing/testing.go:711 +0x2d2
panic(0x53f820, 0x594da0)
/usr/local/go/src/runtime/panic.go:491 +0x283
github.com/yourbasic/bit.(*Set).Max(0xc42000a940, 0x0)
../src/github.com/bit/set_math_bits.go:137 +0x89
github.com/yourbasic/bit.TestMax(0xc420092690)
../src/github.com/bit/set_test.go:165 +0x337
testing.tRunner(0xc420092690, 0x57f5e8)
/usr/local/go/src/testing/testing.go:746 +0xd0
created by testing.(*T).Run
/usr/local/go/src/testing/testing.go:789 +0x2de
複製代碼
能夠從下至上閱讀:數據結構
testing.(*T).Run
調用了 testing.tRunner
,testing.tRunner
調用了 bit.TestMax
,bit.TestMax
調用了 bit.(*Set).Max
,bit.(*Set).Max
調用了 panic
,panic
調用了 testing.tRunner.func1
縮進的行顯示了調用該函數的源文件和行號。十六進制數字表示參數值,包括指針和內部數據結構的值。Go 中的堆棧跟蹤 具備更多詳細信息。框架
要打印當前 goroutine 的堆棧跟蹤,請使用包 runtime/debug 中的debug.PrintStack。函數
您還能夠經過調用 runtime.Stack 以編程方式檢查當前的堆棧跟蹤
變量 GOTRACEBACK 控制 Go 程序失敗時生成的輸出量。
GOTRACEBACK = none
徹底忽略 goroutine 堆棧跟蹤。GOTRACEBACK = single
(默認)爲當前goroutine打印堆棧跟蹤, 從而消除運行時系統內部的功能。若是沒有當前goroutine或故障是運行時內部的,則故障會打印全部goroutine的堆棧跟蹤。GOTRACEBACK = all
爲全部用戶建立的goroutine添加堆棧跟蹤。GOTRACEBACK = system
與其餘系統同樣,可是爲運行時函數添加了堆棧框架,並顯示了運行時在內部建立的 goroutine。內置的 recover 函數可用於從新得到對異常程序的控制並恢復正常執行。
由於展開時運行的惟一代碼是在 defer 函數內部,因此 recover 僅在此類函數內部有用。
func main() {
n := foo()
fmt.Println("main received", n)
}
func foo() int {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
}
}()
m := 1
panic("foo: fail")
m = 2
return m
}
複製代碼
foo: fail
main received 0
複製代碼
因爲 panic 是在 foo 返回值以前發生的,所以 n 仍然具備其初始零值。
要在發生 panic 時返回值,必須使用命名返回值。
func main() {
n := foo()
fmt.Println("main received", n)
}
func foo() (m int) {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
m = 2
}
}()
m = 1
panic("foo: fail")
m = 3
return m
}
複製代碼
foo: fail
main received 2
複製代碼
在此示例中,咱們使用反射來檢查接口變量列表是否具備與給定函數的參數相對應的類型。若是是這樣,咱們使用這些參數調用該函數以檢查是否有 panic。
// Panics tells if function f panics with parameters p.
func Panics(f interface{}, p ...interface{}) bool {
fv := reflect.ValueOf(f)
ft := reflect.TypeOf(f)
if ft.NumIn() != len(p) {
panic("wrong argument count")
}
pv := make([]reflect.Value, len(p))
for i, v := range p {
if reflect.TypeOf(v) != ft.In(i) {
panic("wrong argument type")
}
pv[i] = reflect.ValueOf(v)
}
return call(fv, pv)
}
func call(fv reflect.Value, pv []reflect.Value) (b bool) {
defer func() {
if err := recover(); err != nil {
b = true
}
}()
fv.Call(pv)
return
}
複製代碼
掃描下方二維碼,關注Feed
, 按期推送最新隨筆