error接口:erorr是一种内建的接口类型.内建意味着不需要import.任何包都可以直接使用,使用起来就像int string一样自然.源码位置:src/builtin/builtin.go// The error built-in interface type is the conventional interface for // representing an error condition, with the nil value representing no error. type error interface { Error() string }从源码可知.error接口只声明了一个Error()方法.任何实现了该方法的结构体都可以作为error来使用.error的实例代表一种异常状态.Error()方法用于描述该异常状态.值为nil的error代表没有异常.标准库erroor包中的errorString就是实现error接口的一个例子.源码位置:src/errors/errors.gotype errorString struct { s string } func (e *errorString) Error() string { return e.s }errorString是errors包的私有类型.对外不可见.只能通过相应的公开接口才可以创建errorString实例.
创建error:标准库创建方法:
.errors.New():源码位置:src/errors/errors.go// New returns an error that formats as the given text. // Each call to New returns a distinct error value even if the text is identical. func New(text string) error { return errorString{text} }errors.New()实现比较简单.只是单纯的构建了一个errorString实例便返回了.
.fmt.Errorf():源码位置:src/fmt/errors.gofunc Errorf(format string, a ...any) error { p : newPrinter() p.wrapErrs true p.doPrintf(format, a) s : string(p.buf) var err error switch len(p.wrappedErrs) { case 0: err errors.New(s) case 1: w : wrapError{msg: s} w.err, _ a[p.wrappedErrs[0]].(error) err w default: if p.reordered { slices.Sort(p.wrappedErrs) } var errs []error for i, argNum : range p.wrappedErrs { if i 0 p.wrappedErrs[i-1] argNum { continue } if e, ok : a[argNum].(error); ok { errs append(errs, e) } } err wrapErrors{s, errs} } p.free() return err }fmt.Errorf会接受两个参数然后对string进行格式化.
性能对比:fmt.Errorf()适用于格式化输出错误字符串的场景.如果不需要格式化字符串.则建议直接使用errors.New().示例如下:package Concurrent import ( errors fmt testing ) // 场景1无格式化参数的简单错误errors.New 原生场景 vs fmt.Errorf 无参数 func BenchmarkErrorsNew_Simple(b *testing.B) { // 重置计时器排除初始化耗时 b.ResetTimer() // 循环执行 b.N 次b.N 由基准测试框架自动调整 for i : 0; i b.N; i { _ errors.New(simple error) } } func BenchmarkFmtErrorf_Simple(b *testing.B) { b.ResetTimer() for i : 0; i b.N; i { // fmt.Errorf 无格式化参数等价于 errors.New _ fmt.Errorf(simple error) } } // 场景2带格式化参数的错误fmt.Errorf 核心场景errors.New 无法直接实现 func BenchmarkFmtErrorf_Format(b *testing.B) { // 测试参数字符串数字模拟真实业务格式化场景 msg : user uid : 1001 b.ResetTimer() for i : 0; i b.N; i { _ fmt.Errorf(user %s not found, uid: %d, msg, uid) } } // 场景3带错误包装的场景%w 动词fmt.Errorf 特有 func BenchmarkFmtErrorf_Wrap(b *testing.B) { baseErr : errors.New(base error) b.ResetTimer() for i : 0; i b.N; i { _ fmt.Errorf(wrap error: %w, baseErr) } }
fmt.Errorf():fmt.Errorf()新增了格式动词%w(wrap)用于生成wrapError实例.并且兼容原有动词格式.源码如下:func Errorf(format string, a ...any) error { p : newPrinter() p.wrapErrs true p.doPrintf(format, a) s : string(p.buf) var err error switch len(p.wrappedErrs) { case 0: err errors.New(s) case 1: w : wrapError{msg: s} w.err, _ a[p.wrappedErrs[0]].(error) err w default: if p.reordered { slices.Sort(p.wrappedErrs) } var errs []error for i, argNum : range p.wrappedErrs { if i 0 p.wrappedErrs[i-1] argNum { continue } if e, ok : a[argNum].(error); ok { errs append(errs, e) } } err wrapErrors{s, errs} } p.free() return err }fmt.Errorf()将根据动词格式来动态决定生成wrapError还是errorString.func main() { err : errors.New(this is an error) //使用%v baseError : fmt.Errorf(this is a %v, err) if _, ok : baseError.(interface{ Unwrap() error }); !ok { fmt.Println(baseError is errorString) } }使用%w格式动词生成的error类型自动变成wrapError(实现了Unwrap接口).func main() { err : errors.New(this is an error) //使用%w baseError : fmt.Errorf(this is a %w, err) if _, ok : baseError.(interface{ Unwrap() error }); ok { fmt.Println(baseError is wrapError) } }当error在函数间传递时.error之间好像被组织成一个链式结构.