errors包常用方法

func Unwrap(err error) error                 // 获得err包含下一层错误
func Is(err, target error) bool // 判断err是否包含target
func As(err error, target interface{}) bool // 判断err是否为target类型

自定义错误信息

errors.New("这是自定义错误")

# 使用fmt进行错误包装
fmt.Errorf("error: %w", err)

errors.Is()

作用:判断被包装过的error是否包含指定错误

var BaseErr = errors.New("base error")

func main() {
err1 := fmt.Errorf("wrap base: %w", BaseErr)
err2 := fmt.Errorf("wrap err1: %w", err1)
println(err2 == BaseErr) if !errors.Is(err2, BaseErr) { // err2错误 是否在BaseErr错误树中
panic("err2 is not BaseErr")
}
println("err2 is BaseErr")
} //输出:
//false
//err2 is BaseErr

errors.As()

作用:判断被包装过的error是否为指定类型

具体说明:提取指定类型的错误,判断包装的 error 链中,某一个 error 的类型是否与 target 相同,并提取第一个符合目标类型的错误的值,将其赋值给 target

type TypicalErr struct {
e string
} func (t TypicalErr) Error() string {
return t.e
} func main() {
err := TypicalErr{"typical error"}
err1 := fmt.Errorf("wrap err: %w", err)
err2 := fmt.Errorf("wrap err1: %w", err1)
var e TypicalErr
if !errors.As(err2, &e) {
panic("TypicalErr is not on the chain of err2")
}
println("TypicalErr is on the chain of err2")
println(err == e)
}
//输出:
//TypicalErr is on the chain of err2
//true

errors的最佳实践:

遵循以下建议,我们可以更好地处理 error :

  • 1、一个 error,应该只被处理一次
  • 2、让 error 包含更多的信息
  • 3、原始 error,应保证完整性,不被破坏
  • 4、error 需要被日志记录

为了确保 error 处理的有效性,对于某一层来说,应该保证每个错误只被处理一次,要么打印 error 信息,要么将其传递给上一层,而不是每一层都独立打印 error 信息。

同时,在传递错误给上一层时,应该附带有用的额外信息,并确保不破坏原始错误的完整性,以保证错误的可追溯性。最后,通过记录错误日志可以帮助我们进行问题排查。

我们可以借助第三方库 github.com/pkg/errors 来完成我们的需求。

github.com/pkg/errors 提供了很多实用的函数,例如:

  • Wrap(err error, message string) error:该函数基于原始错误 err,返回一个带有堆栈跟踪信息和附加信息 message 的新 error
  • Wrapf(err error, format string, args ...interface{}) error: 和上面的函数功能是一样的,只不过可以对附加信息进行格式化封装
  • WithMessage(err error, message string) error:该函数基于原始错误 err,返回一个附加信息 message 的新 error
  • WithMessagef(err error, format string, args ...interface{}) error: 和上面的函数功能是一样的,只不过可以对附加信息进行格式化封装
  • Cause(err error) error:该函数用于提取 err 中的原始 error,它会递归地检查 error,直到找到最底层的原始 error,如果存在的话
// controller / middleware
res, err := service.GetById(ctx, id)
if err != nil {
log.Errorf(ctx, "service.GetById failed, original error: %T %v", errors.Cause(err), errors.Cause(err))
log.Errorf(ctx, "stack trace: \n%+v\n", err)
······
}
······ // service
article, err := dao.GetById(ctx, id)
if err != nil {
return errors.WithMessage(err, "dao.GetById failed")
}
······ // dao
······
if err != nil {
return errors.Wrapf(err, "GetById failed, id=%s, error=%v", id, err)
}
······

当在 Dao 层遇到原始错误 Original Error 后,使用 errors.Wrap() 对错误进行封装。这个封装操作可以在保留根因(Origin error)的同时,提供堆栈信息,并添加额外的上下文信息,然后将封装后的错误传递给上一层处理。

service 层接收到 error 之后,使用 errors.WithMessage() 函数,将额外的信息附加到错误上,并继续将错误向上层传递,直至到达 controller 层。在 controller 层,我们可以打印出根因的类型、信息以及堆栈信息,以便更好地进行问题排查。

 
 

golang之errors包的更多相关文章

  1. Golang学习 - errors 包

    ------------------------------------------------------------ Go 语言使用 error 类型来返回函数执行过程中遇到的错误,如果返回的 e ...

  2. 关于golang的time包总结

    目录 前言 time包详解 总结 前言 各种编程语言都少不了与时间有关的操作,因为很多判断都是基于时间,因此正确和方便的使用时间库就很重要额. golang提供了import "time&q ...

  3. Golang爬虫示例包系列教程(一):pedaily.com投资界爬虫

    Golang爬虫示例包 文件结构 自己用Golang原生包封装了一个爬虫库,源码见go get -u -v github.com/hunterhug/go_tool/spider ---- data ...

  4. 一键解决 go get golang.org/x 包失败

    问题描述 当我们使用 go get.go install.go mod 等命令时,会自动下载相应的包或依赖包.但由于众所周知的原因,类似于 golang.org/x/... 的包会出现下载失败的情况. ...

  5. 19-03【golang】strings包

    golang的strings包提供了字符串操作的一系列函数.下面做个简单介绍 函数 用法 备注 Compare(a,b sring) 比较两个字符串   Contains(s, substr stri ...

  6. 关于golang.org/x包问题

    关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...

  7. Golang Gin 项目包依赖管理 godep 使用

    Golang Gin 项目包依赖管理 godep 使用 标签(空格分隔): Go 在按照github.com/tools/godep文档go get完包以后,调整项目结构为$GOPATH/src/$P ...

  8. golang 关于golang.org/x包问题

    关于golang.org/x包问题 由于谷歌被墙,跟谷歌相关的模块无法通过go get来下载,解决方法: git clone https://github.com/golang/net.git $GO ...

  9. Golang的json包

    encoding/json encoding/json是官方提供的标准json, 实现RFC 7159中定义的JSON编码和解码.使用的时候需要预定义struct,原理是通过reflection和in ...

  10. Golang官方log包详解

    Golang官方log包详解 以下全是代码, 详解在注释中, 请从头到尾看 // Copyright 2009 The Go Authors. All rights reserved. // Use ...

随机推荐

  1. C#自定义控件—流动管道

    C#用户控件之流动管道 如何绘制一个动态的流动管道(FlowPipe)? 分两步绘制 定义属性: 画布重绘: 主要技能: 管道的绘制(渐变色矩形) /// <summary> /// 画渐 ...

  2. DVI与VGA有什么区别?

    DVI接口:DVI(Digital Visual Interface),即数字视频接口.DVI接口速度快.画面清晰.支持HDCP协议. VGA接口:VGA(Video Graphics Array)即 ...

  3. 深度学习Python代码小知识点(备忘,因为没有脑子)

    现在是2024年4月24日16:58,今天摸鱼有点多,备忘一下,都写到一篇内容里面,免得分散. 1. np.concatenate()函数'np.concatenate'是NumPy库中用来合并两个或 ...

  4. QT硬件异构计算

    QT硬件异构计算 使用AI技术辅助生成 1 QT硬件异构计算概述 1.1 硬件异构计算概念 1.1.1 硬件异构计算概念 硬件异构计算概念 <QT硬件异构计算>正文 硬件异构计算概念 在进 ...

  5. 提升软件测试效率与灵活性:探索Mock测试的重要性

    Mock测试是测试过程中的一种方法,用于替代那些难以构造或获取的对象,通过创建虚拟对象来进行测试.所谓难以构造的对象如何理解呢? 举例来说,像HttpServletRequest这样的对象需要在具有s ...

  6. php 生成唯一订单号

    php 生成唯一订单号4种方法   第一种 private function doCreateOrderNumber($time){ $i=1; $dd = date('Ymd',$time); $a ...

  7. Android dex、odex、oat、vdex、art区别

    1.dex java程序编译成class后,dx工具将所有class文件合成一个dex文件,dex文件是jar文件大小的50%左右. 2.odex(Android5.0之前)全称:Optimized ...

  8. Oracle 23c 新特性实操体验优质文章汇总 | 有奖征文进行中欢迎参与

    继4月3日甲骨文宣布推出免费开发者版 Oracle Database 23c后,墨天轮社区发起 "Oracle 23c 免费开发者版特性体验"有奖征文活动,邀请大家分享Oracle ...

  9. Office365常用的命令(持续更新中)

    Office365常用的命令(持续更新中) 持续更新中............. Enable-ExchangeCertificate -Thumbprint B9C93420E7BEE46C1CD2 ...

  10. KubeSphere 社区双周报|2024.05.09-05.23

    KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...