对于Go语言(golang)的错误设计,相信很多人已经体验过了,它是通过返回值的方式,来强迫调用者对错误进行处理,要么你忽略,要么你处理(处理也可以是继续返回给调用者),对于golang这种设计方式,我们会在代码中写大量的if判断,以便做出决定。

func main() {conent,err:=ioutil.ReadFile("filepath")if err !=nil{//错误处理}else {fmt.Println(string(conent))}
}

这类代码,在我们编码中是非常的,大部分情况下error都是nil,也就是没有任何错误,但是非nil的时候,意味着错误就出现了,我们需要对他进行处理。

error 接口

error其实一个接口,内置的,我们看下它的定义

// 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。现在我们自己定义一个错误试试。

type fileError struct {
}func (fe *fileError) Error() string {return "文件错误"
}

自定义 error

自定义了一个fileError类型,实现了error接口。现在测试下看看效果。

func main() {conent, err := openFile()if err != nil {fmt.Println(err)} else {fmt.Println(string(conent))}
}//只是模拟一个错误
func openFile() ([]byte, error) {return nil, &fileError{}
}

我们运行模拟的代码,可以看到文件错误的通知。

在实际的使用过程中,我们可能遇到很多错误,他们的区别是错误信息不一样,一种做法是每种错误都类似上面一样定义一个错误类型,但是这样太麻烦了。我们发现Error返回的其实是个字符串,我们可以修改下,让这个字符串可以设置就可以了。

type fileError struct {s string
}func (fe *fileError) Error() string {return fe.s
}

恩,这样改造后,我们就可以在声明fileError的时候,设置好要提示的错误文字,就可以满足我们不同的需要了。

//只是模拟一个错误
func openFile() ([]byte, error) {return nil, &fileError{"文件错误,自定义"}
}

恩,可以了,已经达到了我们的目的。现在我们可以把它变的更通用一些,比如修改fileError的名字,再创建一个辅助函数,便于我们创建不同的错误类型。

//blog:www.flysnow.org
//wechat:flysnow_org
func New(text string) error {return &errorString{text}
}type errorString struct {s string
}func (e *errorString) Error() string {return e.s
}

变成以上这样,我们就可以通过New函数,辅助我们创建不同的错误了,这其实就是我们经常用到的errors.New函数,被我们一步步剖析演化而来,现在大家对Go语言(golang)内置的错误error有了一个清晰的认知了。

存在的问题

虽然Go语言对错误的设计非常简洁,但是对于我们开发者来说,很明显是不足的,比如我们需要知道出错的更多信息,在什么文件的,哪一行代码?只有这样我们才更容易的定位问题。

还有比如,我们想对返回的error附加更多的信息后再返回,比如以上的例子,我们怎么做呢?我们只能先通过Error方法,取出原来的错误信息,然后自己再拼接,再使用errors.New函数生成新错误返回。

如果我们以前做过java开发,我们知道Java的异常是可以嵌套的,也就是说,通过这个,我们很容易知道错误的根本原因,因为Java的异常,是一层层的嵌套返回的,不管中间经历了多少包装,我们可以通过cause找到根本错误的原因。

解决问题

如果要解决以上的问题,那么首先我们必须再继续扩充我们的errorString,再增加一些字段来存储更多的信息。比如我们要记录堆栈信息。

type stack []uintptr
type errorString struct {s string*stack
}

欢迎关注微信公众号flysnow_org或者博客网站 https://www.flysnow.org/ 查看更多原创文章。

有了存储堆栈信息的stack字段,我们在生成错误的时候,就可以把调用的堆栈信息存储在这个字段里。

//blog:www.flysnow.org
//wechat:flysnow_orgfunc callers() *stack {const depth = 32var pcs [depth]uintptrn := runtime.Callers(3, pcs[:])var st stack = pcs[0:n]return &st
}func New(text string) error {return &errorString{s:   text,stack: callers(),}
}

完美解决,现在如果再解决,对现有的错误附加一些信息的问题呢?相信大家应该有思路了。

type withMessage struct {cause errormsg   string
}func WithMessage(err error, message string) error {if err == nil {return nil}return &withMessage{cause: err,msg:   message,}
}

使用WithMessage函数,对原来的error包装下,就可以生成一个新的带有包装信息的错误了。

推荐的方案

以上我们在解决问题是,采取的方法是不是比较熟悉?尤其是看源代码,没错,这就是github.com/pkg/errors这个错误处理库的源代码。

因为Go语言提供的错误太简单了,以至于简单的我们无法更好的处理问题,甚至不能为我们处理错误,提供更有用的信息,所以诞生了很多对错误处理的库,github.com/pkg/errors是比较简洁的一样,并且功能非常强大,受到了大量开发者的欢迎,使用者很多。

它的使用非常简单,如果我们要新生成一个错误,可以使用New函数,生成的错误,自带调用堆栈信息。

func New(message string) error

如果有一个现成的error,我们需要对他进行再次包装处理,这时候有三个函数可以选择。

//只附加新的信息
func WithMessage(err error, message string) error//只附加调用堆栈信息
func WithStack(err error) error//同时附加堆栈和信息
func Wrap(err error, message string) error

其实上面的包装,很类似于Java的异常包装,被包装的error,其实就是Cause,在前面的章节提到错误的根本原因,就是这个Cause。所以这个错误处理库为我们提供了Cause函数让我们可以获得最根本的错误原因。

func Cause(err error) error {type causer interface {Cause() error}for err != nil {cause, ok := err.(causer)if !ok {break}err = cause.Cause()}return err
}

使用for循环一直找到最根本(最底层)的那个error

以上的错误我们都包装好了,也收集好了,那么怎么把他们里面存储的堆栈、错误原因等这些信息打印出来呢?其实,这个错误处理库的错误类型,都实现了Formatter接口,我们可以通过fmt.Printf函数输出对应的错误信息。

%s,%v //功能一样,输出错误信息,不包含堆栈
%q //输出的错误信息带引号,不包含堆栈
%+v //输出错误信息和堆栈

以上如果有循环包装错误类型的话,会递归的把这些错误都会输出。

小结

通过使用这个 github.com/pkg/errors 错误库,我们可以收集更多的信息,可以让我们更容易的定位问题。

我们收集的这些信息不止可以输出到控制台,也可以当做日志,使用输出到相应的Log日志里,便于分析问题。

据说这个库,会被加入到Golang 标准 SDK 里,期待着,如果加入的话,应该就是补充现在标准库里的errors 这个package了。

本文为原创文章,转载注明出处,欢迎扫码关注公众号flysnow_org或者网站asf http://www.flysnow.org/ ,第一时间看后续精彩文章。觉得好的话,请猛击文章右下角「好看」,感谢支持。

扫码关注

Go语言(golang)的错误(error)处理的推荐方案相关推荐

  1. call stack是什么错误_Go语言(golang)的错误(error)处理的推荐方案

    原文链接:https://www.flysnow.org/2019/01/01/golang-error-handle-suggestion.html 微信公众号:flysnow_org(飞雪无情) ...

  2. panic函数c语言,【go语言学习】错误error和异常panic

    一.错误和异常的区别 错误指的是可能出现问题的地方出现了问题.比如打开一个文件时失败,这种情况在人们的意料之中 . 异常指的是不应该出现问题的地方出现了问题.比如引用了空指针,这种情况在人们的意料之外 ...

  3. 想系统学习GO语言(Golang),能推荐几本靠谱的书吗?

    以下内容来自知乎: 链接:https://www.zhihu.com/question/30461290 学习任何一门语言,都要学习好基础,把基础打牢,那些框架对你来说都是工具,你自己的基础好,懂得了 ...

  4. c语言错误2064,VC错误: error C2064: term does not evaluate to a function

    VC错误: error C2064: term does not evaluate to a function0 grcfhl2013.11.03浏览34次分享举报 一个求矩形,圆形,三角形的面积的程 ...

  5. c语言代码错误c2059,c++代码错误error C2059:?

    c++代码错误error C2059:?0 代码如下://Circle.cpp文件,类CCircle的成员函数的实现 #include "circle.h" double CCir ...

  6. Go语言(Golang)的Web框架比较:gin VS echo

    Go语言(Golang)的web框架比较之:gin vs echo 由 butaixianran 在 2016-01-23 22:00 发布 35423 次点击 原文发在:https://771dia ...

  7. [转]Go语言(Golang)的Web框架比较:gin VS echo

    Go语言(Golang)的web框架比较之:gin vs echo 由 butaixianran 在 2016-01-23 22:00 发布 35423 次点击 原文发在:https://771dia ...

  8. java出现errors是什么错误_java中错误(error)和异常(exception)有什么主要区别?

    jdk8中文发翻译Throwable类的描述:Throwable类是Java语言中所有错误和异常的Throwable类. 只有作为此类(或其一个子类)的实例的对象由Java虚拟机抛出,或者可以由Jav ...

  9. c语言中error c2601,C 语言   dd.cpp(46) : error C2601: 'main' : local function definitions are illegal...

    C 语言   dd.cpp(46) : error C2601: 'main' : local function definitions are illegal0 #include #include ...

  10. c语言程序错误提示一个找不到,C语言编辑程序出现错误提示.doc

    C语言编辑程序出现错误提示 Turbo?C?2.0编译错误信息fgh1986% (2007-06-19 21:40:46) 标签: 分类: Turbo C(V2.0)编译错误信息编译错误信息等简易说明 ...

最新文章

  1. 开发安全的 API 所需要核对的清单
  2. 数据库里any 和 all 的区别
  3. 105_键盘事件对象
  4. jupyter 数据分析可视化案例_Python数据分析及可视化实例之Anaconda、Jupyter简介
  5. HTML5来到,原生Native APP是否还有市场
  6. Android利用Filter过滤数据
  7. 【Django 2021年最新版教程6】前端传递数据到后端处理 POST方法
  8. kml文件转成cvs_KMZ KML与SHP文件互相转换
  9. 爬取国家统计局数据正式篇
  10. 根据标题自动生成图片程序,使用教程,并附程序下载
  11. ionic4 监听事件
  12. CentOS7使用Yum安装k8s
  13. 关于绿色建筑的发展促进,从技术厂家角度我们这么看!
  14. flask+python 实时视频流输出到前台
  15. 20230223 作业
  16. iphone系统架构以及各层提供的主要服务
  17. java 给word加水印,Java 实现在线给word 文档添加水印
  18. Java开发编码规范
  19. 14年高考结束了,明日边缘看完了,明天周一了 (2014-06-08)
  20. 让别人叫爸爸的恶搞程序,第一天写程序,免费分享给大家,希望喜欢的一键三连多多支持。

热门文章

  1. ios 加载大量图片崩溃_iOS 加载过大图片闪退
  2. python爬虫获取数据失败请稍后访问_Python爬取微博评论数据,竟被反爬封号了!...
  3. Java中的成员变量和局部变量
  4. 使用带有响应的Hypermedia API来保留v6
  5. word中安装Zotero插件
  6. 梳理企业业务流程四步法
  7. 基础测绘数据分类标准
  8. 诛仙2服务器不显示列表,诛仙2 服务器列表
  9. 常见的用户密码加密方式以及破解方法
  10. LOTO课6:一只三极管的输出特性曲线的测绘