packagemainimport"fmt"funcfullName(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")}funcmain() { firstName :="Elon"fullName(&firstName, nil) fmt.Println("returned normally from main")}
packagemainimport"fmt"funcfullName(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")}funcmain() {defer fmt.Println("deferred call in main") firstName :="Elon"fullName(&firstName, nil) fmt.Println("returned normally from main")}
该程序执行结果如下:
deferred call in fullName
deferred call in main
panic: runtime error: last name cannot be nil
goroutine 1 [running]:
main.fullName(0xc000074f58, 0x0)
/Users/work/goWorkspace/src/test/main.go:11 +0x1d1
main.main()
/Users/work/goWorkspace/src/test/main.go:20 +0xa5
exit status 2
这段程序中fullName发生panic时先执行被defer的函数调用,打印了deferred call in fullName。然后程序执行控制权转移给外层函数,接着执行外层函数被defer的函数调用,打印了deferred call in main。此时已到goroutine级别,因此不会再接着向外冒泡了。接着打印了panic信息以及调用栈。
packagemainimport"fmt"funcrecoverName() {if r :=recover(); r !=nil { fmt.Println("recovered from ", r) }}funcfullName(firstName *string, lastName *string) {deferrecoverName()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")}funcmain() {defer fmt.Println("deferred call in main") firstName :="Elon"fullName(&firstName, nil) fmt.Println("returned normally from main")}
Inside A
Inside B
panic: oh! B panicked
goroutine 5 [running]:
main.b()
/Users/work/goWorkspace/src/test/main.go:23 +0x79
created by main.a
/Users/work/goWorkspace/src/test/main.go:17 +0x95
exit status 2
如果b函数调用不是在一个新的goroutine,比如我们将go b()改为b(),则执行结果如下:
Inside A
Inside B
recovered: oh! B panicked
normally returned from main
typeErrorinterface { error// RuntimeError is a no-op function but// serves to distinguish types that are run time// errors from ordinary errors: a type is a// run time error if it has a RuntimeError method.RuntimeError()}
packagemainimport"fmt"funca() { n := []int{5, 7, 4} fmt.Println(n[3]) fmt.Println("normally returned from a")}funcmain() {a() fmt.Println("normally returned from main")}
这里我们访问切片n的索引为3的位置,显然越界了。因此引发运行时panic。该程序输出如下:
panic: runtime error: index out of range
goroutine 1 [running]:
main.a()
/Users/work/goWorkspace/src/test/main.go:7 +0x11
main.main()
/Users/work/goWorkspace/src/test/main.go:11 +0x22
exit status 2
运行时panic也可以通过recover来恢复。
packagemainimport"fmt"funcr() {if r :=recover(); r !=nil { fmt.Println("Recovered", r) }}funca() {deferr() n := []int{5, 7, 4} fmt.Println(n[3]) fmt.Println("normally returned from a")}funcmain() {a() fmt.Println("normally returned from main")}
这里我们在被defer的函数r中将panic的程序恢复正常。该程序输出为:
Recovered runtime error: index out of range
normally returned from main
packagemainimport ( "fmt""runtime/debug")funcr() { if r :=recover(); r !=nil { fmt.Println("Recovered", r) debug.PrintStack() }}funca() { deferr() n := []int{5, 7, 4} fmt.Println(n[3]) fmt.Println("normally returned from a")}funcmain() { a() fmt.Println("normally returned from main")}
这里我们通过debug.PrintStack()来手动打印了调用栈。该程序输出如下:
Recovered runtime error: index out of range
goroutine 1 [running]:
runtime/debug.Stack(0xc00007a008, 0xc00006ee08, 0x2)
/usr/local/go/src/runtime/debug/stack.go:24 +0xa7
runtime/debug.PrintStack()
/usr/local/go/src/runtime/debug/stack.go:16 +0x22
main.r()
/Users/work/goWorkspace/src/test/main.go:11 +0x9c
panic(0x10a9bc0, 0x115d560)
/usr/local/go/src/runtime/panic.go:513 +0x1b9
main.a()
/Users/work/goWorkspace/src/test/main.go:18 +0x3e
main.main()
/Users/work/goWorkspace/src/test/main.go:23 +0x22
normally returned from main