1 目标
自定义错误信息,以满足针对不同error进行不同的处理,或更多的错误信息输出。
2 原生error
- 实现了以下func的任意类型,即可认为实现了error,且可使用errors包
type error interface {
Error() string
}
3 errors包中Is\As比较的过程按以下顺序的三个条件进行判断,满足便退出:
- 条件一:自定义类型无实现Is\As方法,直接进行比较。
- 条件二:自定义类型实现Is\As方法,则调用err1.Is(err2)\err2.As(err2)。
- 条件三:当前错误是否为errors.Join(…error)得到的错误,则会遍历错误链,递归调用errors.is(),重复判断过程;错误链之一满足条件即可退出。
4 故自定义函数需自行实现Is\As函数,用于自定义判断,完整函数代码如下:
package cerrors
import (
"errors"
"fmt"
"time"
)
type CError struct {
Code int
Msg string
Time time.Time
Type string
}
// 满足interface
func (e *CError) Error() string {
s := fmt.Sprintf("type %s, msg %s, time %s", e.Type, e.Msg, e.Time.Format("2006-01-02 15:04:05"))
return s
}
// errors.Is 默认最简情况:仅支持精确匹配 指针地址或值是否相等
// 自定义类型实现Is,可以进行更精细化的比较条件
func (e *CError) Is(target error) bool {
var te *CError
// 自定义错误类型比较
if errors.As(target, &te) {
return e.Code == te.Code && e.Type == te.Type
}
// 官方类型、其它类型直接返回错误
return false
}
// errors.As 默认最简情况:仅支持类型完全匹配 二者的类型是否一致
// 自定义类型实现As,可以进行更精细化的类型转换
// target必须是双指针,即指针的指针
func (e *CError) As(target any) bool {
// 判断target是否是指针的指针
// 判断target是否能转成*CError,同种类型才能够从a转到target
te, ok := target.(**CError)
if !ok {
return false
}
*te = e
return true
}
const (
CodeInfo = 0
CodeWarning = 1
CodeError = 2
)
const (
TypeInfo = "info"
TypeWarning = "warning"
TypeError = "error"
)
func NewError(t string, msg string, code uint) *CError {
return &CError{
Msg: msg,
Type: t,
Time: time.Now(),
}
}
func Info(msg string) *CError {
return NewError(TypeInfo, msg, CodeInfo)
}
func Warning(msg string) *CError {
return NewError(TypeWarning, msg, CodeWarning)
}
func Error(msg string) *CError {
return NewError(TypeError, msg, CodeError)
}