Go语言如何简化包装错误自定义类型的冗余实现代码?
Go语言减少错误包装冗余代码的两种常用方案
方案1:结构体嵌入复用公共逻辑(兼容原有类型断言用法)
Go虽然不支持类继承,但可以通过结构体嵌入的方式复用公共方法,你只需要定义一个基础包装结构体实现通用的Error()和Unwrap()方法,后续业务自定义的错误包装类型直接嵌入该基础结构体即可,无需重复实现接口方法。
代码示例:
// 公共基础包装结构体,实现通用逻辑 type BaseWrap struct { WrappedErr error } func (b BaseWrap) Error() string { return b.WrappedErr.Error() } func (b BaseWrap) Unwrap() error { return b.WrappedErr } // 自定义业务包装类型,一行定义即可,无需重复实现方法 type WrapA struct { BaseWrap } type WrapB struct { BaseWrap }
原有doStuff和main逻辑几乎不需要修改,只需要在包装错误时传入基础结构体即可:
func doStuff() error { err := a() if err != nil { return WrapA{BaseWrap{WrappedErr: err}} } err = b() if err != nil { return WrapB{BaseWrap{WrappedErr: err}} } return nil } // 原有类型断言逻辑完全不变 func main() { fmt.Println("Hello, playground") err := doStuff() switch err.(type) { case WrapA: fmt.Println("error from doing a") case WrapB: fmt.Println("error from doing b") case nil: fmt.Println("nil") default: fmt.Println("unknown") } }
后续新增错误来源只需要加一行type WrapX struct { BaseWrap }即可,完全没有冗余代码。
方案2:哨兵错误+%w包装(无需定义结构体,更简洁)
如果你不需要给错误包装类型附加额外的自定义字段,只是需要区分错误来源,可以用更轻量的哨兵错误方案,不需要定义任何结构体:
// 定义不同来源的哨兵错误 var ( ErrSourceA = errors.New("source a error") ErrSourceB = errors.New("source b error") ) func doStuff() error { err := a() if err != nil { // 用fmt.Errorf的%w同时包装哨兵错误和原始错误 return fmt.Errorf("%w: %w", ErrSourceA, err) } err = b() if err != nil { return fmt.Errorf("%w: %w", ErrSourceB, err) } return nil } // 主逻辑用errors.Is判断错误来源即可 func main() { fmt.Println("Hello, playground") err := doStuff() switch { case errors.Is(err, ErrSourceA): fmt.Println("error from doing a") case errors.Is(err, ErrSourceB): fmt.Println("error from doing b") case err == nil: fmt.Println("nil") default: fmt.Println("unknown") } }
该方案代码量更少,适合不需要自定义错误属性的轻量场景。
内容的提问来源于stack exchange,提问作者magum
相关产品推荐
相关产品推荐

