package main import ( "fmt" ) func divide(num1 int, num2 int) { result := num1 / num2 fmt.Printf("%+v / %+v = %+v \n", num1, num2, result) } func main() { divide(1024, 0) // panic: runtime error: integer divide by zero // 重要说明:下面的代码是执行不到的,因为上面出现了panic fmt.Println("后续逻辑……") }
package main import ( "fmt" ) func divide(num1 int, num2 int) { // 使用defer和recover()实现捕获panic错误 defer func() { err := recover() if err != nil { fmt.Println("程序粗错辣~~~", err) // 程序粗错辣~~~ runtime error: integer divide by zero } else { fmt.Println("程序狠正常~~~") } }() result := num1 / num2 // 重要说明:当上面出现除数为零的情况时,下面的打印操作是不会执行的 fmt.Printf("%+v / %+v = %+v \n", num1, num2, result) } func main() { divide(1024, 0) // 重要说明:由于divide()函数使用defer和recover()捕获了panic,所以即使除数为零也不会中止程序执行 fmt.Println("后续逻辑……") // 后续逻辑…… }
package main import ( "errors" "fmt" ) func func1(num1 int64, num2 int64) (result int64, err error) { defer func() { rec := recover() if rec != nil { value, ok := rec.(error) // 断言rec变量为error类型 if ok { err = value } else { err = errors.New("未知错误") } } }() result, err = func2(num1, num2) return } func func2(num1 int64, num2 int64) (result int64, err error) { result, err = func3(num1, num2) return } func func3(num1 int64, num2 int64) (result int64, err error) { result = num1 / num2 // 重要说明:当num2为0时会发生panic,并被func1()的defer-recover()捕获 err = nil return result, nil } func main() { num1 := int64(1024) num2 := int64(0) result, err := func1(num1, num2) if err != nil { fmt.Println("程序粗错辣~~~", err) // 程序粗错辣~~~ runtime error: integer divide by zero } else { fmt.Printf("%d / %d = %d \n", num1, num2, result) } } // ========== 说明 ========== // // 1、defer-recover()可以捕获其所在调用链里任意位置发生的错误,如上面虽然是在func1()里写defer-recover(), // 但是func3()里发生的错误也能捕获到,因为func1()、func2()、func3()是在一个调用链内。 // 正因为defer-recover()有效范围是整个调用链,所以一般只需在调用链顶层实现捕获错误功能即可,不需要到处写defer-recover()。
package main import ( "fmt" "time" ) func main() { // 创建父协程 go func(num1 int64, num2 int64) { // 重要说明:父协程里的defer-recover()不能捕获子协程的错误 defer func() { err := recover() if err != nil { fmt.Println("程序粗错辣~~~", err) } }() // 创建子协程 go func(num1 int64, num2 int64) { fmt.Println(num1 / num2) // panic: runtime error: integer divide by zero }(num1, num2) }(int64(1024), int64(0)) time.Sleep(time.Second * 3) // 休眠3秒钟,让协程有充足时间执行 } // ========== 说明 ========== // // 1、不管是父子协程还是兄弟协程,每个协程有自己的栈空间和执行路径,也就是每个协程是一个单独的调用链, // 协程的defer-recover()有效范围仅限自身,不会影响父子或兄弟,即每个协程要写自己的defer-recover()。
Copyright © 2024 码农人生. All Rights Reserved