原文连接:www.flysnow.org/2019/01/01/…
微信公众号:flysnow_org(飞雪无情)html
对于Go语言(golang)的错误设计,相信不少人已经体验过了,它是经过返回值的方式,来强迫调用者对错误进行处理,要么你忽略,要么你处理(处理也能够是继续返回给调用者),对于golang这种设计方式,咱们会在代码中写大量的if
判断,以便作出决定。java
func main() {
conent,err:=ioutil.ReadFile("filepath")
if err !=nil{
//错误处理
}else {
fmt.Println(string(conent))
}
}
复制代码
这类代码,在咱们编码中是很是的,大部分状况下error
都是nil
,也就是没有任何错误,可是非nil
的时候,意味着错误就出现了,咱们须要对他进行处理。git
error
其实一个接口,内置的,咱们看下它的定义github
// 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
。如今咱们本身定义一个错误试试。golang
type fileError struct {
}
func (fe *fileError) Error() string {
return "文件错误"
}
复制代码
自定义了一个fileError
类型,实现了error
接口。如今测试下看看效果。bash
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
或者博客网站 www.flysnow.org/ 查看更多原创文章。
有了存储堆栈信息的stack
字段,咱们在生成错误的时候,就能够把调用的堆栈信息存储在这个字段里。
//blog:www.flysnow.org
//wechat:flysnow_org
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := 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 error
msg 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 www.flysnow.org/ ,第一时间看后续精彩文章。以为好的话,请猛击文章右下角「好看」,感谢支持。