
error版本工程迁移
老版本开发的go程序如果想使用链式error,那么需要对旧版本工程做一些适配
- 创建error时,fmt.Errorf()格式化动词由%v修改为%w
- 等值(==)检查可以使用errors.Is()替代
- 类型断言可以使用errors.As()替代
- 自定义类型额外实现Unwrap()方法
- 自定义类型额外实现As()方法
- 自定义类型额外实现Is()方法
1.传递error
旧工程使用%v动词来组装error并传递,迁移时可以直接改为%w动词
if err != nil { return fmt.Errorf("decompress %v: %w",name, err) }虽然旧工程中返回的是errors.errorString类型,而新工程中返回的是fmt.wrapError,但不影响上游使用,fmt.wrapError完全兼容errors.errorString
2.等值检查
等值检查可以直接使用errors.Is()替换
if errors.Is(err, os.ErrPermission) { //permission denied }由于errors.Is()会先拿err与目标值进行比较,不相等才会逐层拆解err并与目标值进行比较,所以使用errors.Is()没有副作用,即便err不是链式error
3.类型断言
类型断言替换成errors.As()时需要先声明一个目标类型的指针变量
var target *os.PathError if errors.As(err,&target){ fmt.Printf("it's an os.PaathError, operation %s, path: %s, msg: %v\n",target.Op,target.Path,target.Err) }
4.自定义类型
对于自定义类型,可以参考wrapError的实现,增加Unwrap()函数
type wrapError struct { msg string err error } func (e *wrapError) Error() string { return e.msg } func (e *wrapError) Unwrap() error{ return e.err }此外,自定义类型还可以实现自己的Is和As接口:
Is(error) bool As(interface{}) bool在实际场景中,几乎不需要实现这两个接口