《Go语言四十二章经》第十五章 错误处理
15.1 错误类型
任何时候当你需要一个新的错误类型,都可以用 errors(必须先 import)包的 errors.New 函数接收合适的错误信息来创建,像下面这样:
err := errors.New("math - square root of negative number")
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New ("math - square root of negative number")
}
}
用 fmt 创建错误对象:
通常你想要返回包含错误参数的更有信息量的字符串,例如:可以用 fmt.Errorf() 来实现:它和 fmt.Printf() 完全一样,接收有一个或多个格式占位符的格式化字符串和相应数量的占位变量。和打印信息不同的是它用信息生成错误对象。 比如在前面的平方根例子中使用:
if f < 0 {
return 0, fmt.Errorf("square root of negative number %g", f)
}
15.2 Panic
在Go语言中 panic() 是一个内置函数,用来表示非常严重的不可恢复的错误。必须要先声明defer,否则不能捕获到异常。普通函数在执行的时候发生了异常,则开始运行defer(如有),defer处理完再返回。
在多层嵌套的函数调用中调用 panic(),可以马上中止当前函数的执行,所有的 defer 语句都会保证执行并把控制权交还给接收到异常的函数调用者。这样向上冒泡直到最顶层,并执行(每层的) defer,在栈顶处程序崩溃,并在命令行中用传给异常的值报告错误情况:这个终止过程就是 panicking。
一般不要随意用 panic() 中止程序,必须尽力 补救错误让程序能继续执行。
自定义包中的错误处理和 panicking,这是所有自定义包实现者应该遵守的最佳实践:
1)在包内部,总是应该从异常中 recover:不允许显式的超出包范围的 panic()
2)向包的调用者返回错误值。
recover() 函数的调用仅当它在 defer 函数中被直接调用时才有效。
下面主函数捕获了异常:
package main
import (
"fmt"
)
func div(a, b int) {
defer func() {
if r := recover(); r != nil {
fmt.Printf("捕获到异常:%s\n", r)
}
}()
if b < 0 {
panic("除数需要大于0")
}
fmt.Println("余数为:", a/b)
}
func main() {
// 捕捉内部的异常
div(10, 0)
// 捕捉主动的异常
div(10, -1)
}