func fullName(firstName *string, lastName *string) { if firstName == nil { panic("runtime error: first name cannot be nil") } if lastName == nil { panic("runtime error: last name cannot be nil") } fmt.Printf("%s %s\n", *firstName, *lastName) fmt.Println("returned normally from fullName") }
func slicePanic() { n := []int{5, 7, 4} fmt.Println(n[4]) fmt.Println("normally returned from a") } func main() { slicePanic() fmt.Println("normally returned from main") }
例子中试图访问切片中n[4]的无效索引,则该程序将有以下输出:
1 2 3 4 5 6 7
panic: runtime error: index out of range [4] with length 3
func fullName(firstName *string, lastName *string) { defer fmt.Println("deferred call in fullName") if firstName == nil { panic("runtime error: first name cannot be nil") } if lastName == nil { panic("runtime error: last name cannot be nil") } fmt.Printf("%s %s\n", *firstName, *lastName) fmt.Println("returned normally from fullName") }
func main() { defer fmt.Println("deferred call in main") firstName := "SS" fullName(&firstName, nil) fmt.Println("returned normally from main") }
上例唯一更改是添加了defer函数调用,现在的输出为:
1 2 3 4 5 6 7 8 9
deferred call in fullName deferred call in main panic: runtime error: last name cannot be nil
func recoverFullName() { if r := recover(); r!= nil { fmt.Println("recovered from ", r) } }
func fullName(firstName *string, lastName *string) { defer recoverFullName() if firstName == nil { panic("runtime error: first name cannot be nil") } if lastName == nil { panic("runtime error: last name cannot be nil") } fmt.Printf("%s %s\n", *firstName, *lastName) fmt.Println("returned normally from fullName") }
func main() { defer fmt.Println("deferred call in main") firstName := "SS" fullName(&firstName, nil) fmt.Println("returned normally from main") }
recovered from runtime error: last name cannot be nil
执行后recover(),panic停止,控制权返回给调用者,在这种情况下,是main函数。程序从 fmt.Println(“returned normally from main”) 开始继续正常执行,main的panic已经recover了。它打印returned normally from main 后跟deferred call in main
func recoverFullName() { if r := recover(); r != nil { fmt.Println("recovered from ", r) debug.PrintStack() } }
func fullName(firstName *string, lastName *string) { defer recoverFullName() if firstName == nil { panic("runtime error: first name cannot be nil") } if lastName == nil { panic("runtime error: last name cannot be nil") } fmt.Printf("%s %s\n", *firstName, *lastName) fmt.Println("returned normally from fullName") }
func main() { defer fmt.Println("deferred call in main") firstName := "SS" fullName(&firstName, nil) fmt.Println("returned normally from main") }
在上面的例子中,使用debug.PrintStack()打印堆栈信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
recovered from runtime error: last name cannot be nil goroutine 1 [running]: runtime/debug.Stack(0x37, 0x0, 0x0) /usr/local/go-faketime/src/runtime/debug/stack.go:24 +0x9d runtime/debug.PrintStack() /usr/local/go-faketime/src/runtime/debug/stack.go:16 +0x22 main.recoverFullName() /tmp/sandbox771195810/prog.go:11 +0xb4 panic(0x4a1b60, 0x4dc300) /usr/local/go-faketime/src/runtime/panic.go:969 +0x166 main.fullName(0xc0000a2f28, 0x0) /tmp/sandbox771195810/prog.go:21 +0x1cb main.main() /tmp/sandbox771195810/prog.go:30 +0xc6 returned normally from main deferred call in main
从输出中可以了解到panic被恢复并recovered from runtime error: last name cannot be nil打印出来了之后,打印堆栈跟踪。然后在panic恢复后打印