call stack是什么错误_Go语言(golang)的错误(error)处理的推荐方案
原文链接:https://www.flysnow.org/2019/01/01/golang-error-handle-suggestion.html
微信公众号:flysnow_org(飞雪无情)
对于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/,第一时间看后续精彩文章。觉得好的话,请猛击文章右下角「好看」,感谢支持。
call stack是什么错误_Go语言(golang)的错误(error)处理的推荐方案相关推荐
- 写c语言会出现哪些常见错误,C语言编写常见错误
C51语言编写常见错误 一.循环 1).在进行while,do...while循环时要对while括号里面的变量赋初值,否则可能出现的不是自己想要的结果. 2).在写for循环语句中,特别要注意括号里 ...
- go http 处理w.write 错误_Go语言中的异常和错误处理简介
女主宣言 异常和错误处理在保证程序的鲁棒性方面起到了至关重要的作用.C++.Java.Python中的异常和错误处理都是比较类似的,可以用try-catch逻辑操作,但是Go中的异常处理却有别于以上三 ...
- c语言Max错误,C语言编程常见错误.pdf
C 语言常见错误 版权声明:以下内容来自互联网 C 语言的最大特点是:功能强.使 方便灵活.C 编译的程序对语法检查并不象其它高级语言那么严 格,这就给编程人员留下 "灵活的余地" ...
- c语言链表错误,C语言创建链表错误之通过指针参数申请动态内存实例分析
本文实例讲述了C语言创建链表中经典错误的通过指针参数申请动态内存,分享给大家供大家参考之用.具体实例如下: #include #include // 用malloc要包含这个头文件 typedef s ...
- c语言编译器可以查出所有什么错误,C语言编译器的错误信息
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 Not a valid expression format type 不合法的表达式格式 Not an allowed type 不允许使用的类型 Num ...
- c语言编程过程中的常见错误,C语言编程常见错误与解决办法
warning: excess elements in array initializer 警告:数组初始值设定项中有多余元素 (定义的数组长度比赋值的个数小) 数组定义出错 "confli ...
- C语言上机错误,C语言上机常见错误和程序调试
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 1常见错误分析 (1) 忘记定义变量. (2) 输入输出的数据的类型与所用格式说明符不一致. (3) 未注意int型数据的数值范围. (4) 在输入语句s ...
- c语言编程中野指针错误,C语言(野指针错误)
realloc引起的coredump 记录一次接口程序在运行过程中产生的崩溃问题,通过调试 core文件,定位到是程序在调用realloc 时候出现了问题 问题程序代码 #include #inclu ...
- 常见c语言语法错误,C语言常犯错误(二)——语法错误
一:理解函数声明: float num1,num2;//含义:对其求值时num1,num2是浮点型的. float ((num1)); //含义:对其求值时((num1))是浮点型的,由此可知num1 ...
最新文章
- linux简单设计与实现代码,《linux内核设计与实现》第五章(示例代码)
- python 参数个数 同名函数_如何在python中编写不同参数的同名方法
- 对比云备份:企业做出最佳选择
- Eclipse:Target runtime XXX is not defined
- 【Java】switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上
- (转)Spring Boot(七):Mybatis 多数据源最简解决方案
- 【零基础学Java】—字符串的概述和特点(十五)
- 腾讯 监控系统服务器数据采集,日均采集1200亿数据点,腾讯千亿级服务器监控数据存储实践...
- Amazon验证码机器算法识别
- matlab坐标轴非均匀分布,matalb——生成离散非均匀随机数
- ECCV 2018 论文下载及分析(774篇全)
- python读取odb_ABAQUS+Python+Script中ODB处理手册
- 2022茶艺师(初级)考试试题模拟考试平台操作
- JAVA定时任务的创建方式
- UGUI之菜单动画效果制作思路
- 爬虫爬取二次元网站美女图片
- 硬核干货:网易云音乐如何做产品创新
- Linux远程ssh破解
- 汤姆斯的天堂梦(par)
- cib.xml for 2resource2group4score