package main
import "fmt"
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 := "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信息以及调用栈。
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
type Error interface {
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()
}
package main
import "fmt"
func a() {
n := []int{5, 7, 4}
fmt.Println(n[3])
fmt.Println("normally returned from a")
}
func main() {
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来恢复。
package main
import "fmt"
func r() {
if r := recover(); r != nil {
fmt.Println("Recovered", r)
}
}
func a() {
defer r()
n := []int{5, 7, 4}
fmt.Println(n[3])
fmt.Println("normally returned from a")
}
func main() {
a()
fmt.Println("normally returned from main")
}
这里我们在被defer的函数r中将panic的程序恢复正常。该程序输出为:
Recovered runtime error: index out of range
normally returned from main
package main
import (
"fmt"
"runtime/debug"
)
func r() {
if r := recover(); r != nil {
fmt.Println("Recovered", r)
debug.PrintStack()
}
}
func a() {
defer r()
n := []int{5, 7, 4}
fmt.Println(n[3])
fmt.Println("normally returned from a")
}
func main() {
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