错误处理
Go语言中,error 是一个接口
type error interface {
Error() string
}
errors 是标准库的一个包,errorString 结构体是对 error接口的实现,我们也可以对 error 接口进行自定义实现
package errors
func New(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
我们可以使用 errors.New 来表示一个最基本的错误,
// 返回 error接口(引用类型)
var err = errors.New("404 Not Found")
错误嵌套
-
Wrap 一个错误链
func test() error { // 有格式化需求时使用 fmt.Errorf 和 %w 来将一个错误 wrap 至错误链中 err0 := err err1 := fmt.Errorf("第一层格式化输出 %w", err0) err2 := fmt.Errorf("第二层格式化输出 %w", err1) return err2 }
-
Unwrap 一个错误链
err1 := errors.Unwrap(err2) err0 := errors.Unwrap(err1)
- 使用
errors.Is判定错误链上的所有错误是否包含有特定的错误(特定是指地址相同的同一个实例) - 使用
errors.As在错误链上获取指定类型的错误
panic函数用于指示无法修复的错误,直接中断程序执行
recover函数用于捕获panic,避免程序崩溃异常退出
完整代码如下:
// 返回 error接口(引用类型)
var err = errors.New("404 Not Found")
func test() error {
// 有格式化需求时使用 fmt.Errorf 和 %w 来将一个错误 wrap 至错误链中
err0 := err
err1 := fmt.Errorf("第一层格式化输出 %w", err0)
err2 := fmt.Errorf("第二层格式化输出 %w", err1)
return err2
}
func main() {
err2 := test()
if err2 != nil { // Unwrap 一个错误链
fmt.Println(err2)
err1 := errors.Unwrap(err2)
fmt.Println(err1)
err0 := errors.Unwrap(err1)
fmt.Println(err0)
// 判定错误链上的所有错误是否包含有特定的错误,特定是指同一个实例(地址相同),从源码可以看出是对接口使用==进行比较的
if errors.Is(err2, err) {
// 在错误链上获取指定类型的错误
var getErr error
if errors.As(err2, &getErr) {
fmt.Println(getErr)
}
}
}
defer func() {
// recover 函数用于捕获并处理 panic,而不是直接崩溃异常退出
// recover 只能在被 defer 的函数中使用,并且只有在发生panic时、在当前协程生效
// 在其他情况下调用recover函数将不会产生任何效果。
rc := recover()
switch rc.(type) {
case runtime.Error: // 运行时错误
fmt.Println("runtime error:", rc)
default: // 非运行时错误
fmt.Println("recover:", rc)
}
}()
// panic 用于出现异常时中断程序,直接执行 defer 后的代码
panic("无法修复的错误")
}