顺晟科技
2021-08-28 09:40:45
333
我认为很多人已经经历过golang语言(Golang)的错误设计。通过返回值强制调用方处理错误。可以忽略或处理(处理也可以继续返回给调用方)。对于Golang的这种设计方式,我们将在代码中写很多if判断。(威廉莎士比亚、Northern Exposure(美国电视剧)、Northern Exposure(美国电视剧))。
1
2
3
4
5
6
7
8
Func main() {
Conent,err 3360=io util . read file(“文件路径”)
If err!=nil{
//错误处理
}else {
Fmt。Println(string(conent))
}
}
这些代码在我们的代码中很重要。大多数情况下,error为nil。这意味着没有任何错误,但如果不是nil,则发生了错误。我们必须处理他(大卫亚设,北方执行)。
错误接口
Error实际上是一个接口,是内置的。让我们来看看它的定义。
1
2
3
4
5
//the error built-in interface type is the conventional interface for
//representing an error condition,with the nil value re presenting no error。
Type error介面{
Error() string
}
Error只有一种方法。实施此方法就是实施Error。约翰肯尼迪,北方执行。现在让我们自己定义错误。
1
2
3
4
5
6
Type fileError struct {
}
Func (Fe * fileerror)错误()字符串{
Return“文件错误”
}
自定义错误
定制文件错误类型以实现错误接口。现在来试试效果。
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)错误()字符串{
Return fe.s
}
是的,这样改造后,我们在声明文件管理器时,可以设置错误的文字来提示,以满足我们的其他要求。(大卫亚设,北上广深)。
//只模拟一个错误
Func openFile() ([]byte,error) {
Return nil,fileError{“文件错误,自定义”}
}
是的,是的。已经达到了我们的目的。现在可以更常见,包括修改fileError的名称和创建可以轻松创建其他错误类型的辅助函数。
//blog 3360 www . flysnow . org
//wechat 3360 flysnow _ org
Funcnew(文本字符串)错误{
Return errorstring {文本}
}
Type errorString struct {
S string
}
Func (e * errorstring)错误()字符串{
Return e.s
}
这样,我们就可以通过New函数创建其他错误。这就是我们经常使用的errors。是New函数,是我们逐步解剖进化而来的。现在,我们对Go语言(golang)中内置的错误error有了明确的认识。(威廉莎士比亚,《北方执行报》(Northern Exposure))。
存在的问题
Go语言在错误的设计上很简洁,但对我们开发者来说显然不够。例如,您需要知道错误的详细信息、哪些文件、需要哪些代码行。(大卫亚设,Northern Exposure(美国电视剧),只有这样,我们才能更容易找到问题。
例如,如果想在返回的error中添加更多信息并返回,如上例所示,我们该怎么办?首先,通过Error方法删除原始错误消息,然后直接连接,最后返回errors。可以使用New函数生成新的错误返回。
如果我们以前开发过Java,我们知道Java的例外可能会重叠。也就是说,通过它,我们可以很容易地知道错误的根本原因。因为Java的理想是重叠返回的。不管中间经历了多少包装,我们都可以通过cause找到根本错误的原因。(阿尔伯特爱因斯坦,北方执行)。
解决问题
要解决这些问题,必须先继续扩展errorString,然后添加要保存其他信息的字段。例如,必须记录堆栈信息。
Type stack []uintptr
Type errorString struct {
S string
*stack
}
//www.oicqzone.com
存储堆栈信息的stack字段允许您在生成错误时调用的堆栈信息存储在此字段中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//blog 3360 www . flysnow . org
//wechat 3360 flysnow _ org
Func callers() *stack {
Const depth=32
Var PCs [depth]uintptr
N:=runtime.callers (3,PCs[3360])
Var ST stack=PCs [03360n]
Return ST
}
Funcnew(文本字符串)错误{
Return errorString{
S:文本,
Stack: callers(),
}
}
完美解决,现在再解决,给现有错误附加一些信息的问题呢?(*译者:译者:译者:译者:译者:译者)我相信大家都要有想法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Type withMessage struct {
Cause error
Msg字符串
}
func withmessage(error,消息字符串)error {
If err==nil {
Return nil
}
Return withMessage{
Cause: err,
Msg :消息,
}
}
使用WithMessage函数可以生成原始error软件包下包含包装信息的新错误。
推荐的方案
上面我们在解决问题,是不是采取的方法比较熟悉?特别是从源代码来看,这就是github.com/pkg/errors错误处理库的源代码。
Go语言提供的错误太简单,不能简单地更好地处理问题,甚至不能处理错误,提供更有用的信息,因此,诞生了很多关于错误处理的库。github.com/pkg/errors比较简洁,功能非常强大,受到了很多开发者的欢迎。
它的使用很简单。要生成新错误,可以使用New函数、生成的错误和自己的调用堆栈信息。
1
Funcnew(消息字符串)错误
如果有现成的error,我们需要重新包装他,这时可以选择三个函数。
1
2
3
4
5
6
7
8
//仅添加新信息
Func withmessage (err error、message string) error
//仅添加调用堆栈信息
Func WithStack(err error) error
//同时添加堆栈和信息
Funcwrap (err error、message string) error
事实上,上面的包装与Java的异常包装非常相似,包装的error实际上是Cause。上一章提到错误的根本原因就是这个Cause。因此,该错误处理库为我们提供了Cause函数,使我们能够获得最根本的错误原因。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Funccause(错误)错误{
Type causer界面{
Cause() error
}
For err!=nil {
Cause,ok :=err。(causer)
If!Ok {
布雷克
}
Err=cause。Cause()
}
Return err
}
使用For循环找到最根本的(底部)错误。
上面的错误我们都打包收集了,怎么能打印出存储在他们里面的堆栈、错误的原因等这些信息呢?实际上,此错误处理库的错误类型实现了Formatter接口,并使用fmt .可以通过Printf函数输出相应的错误消息。
%s,%v //功能一样,输出错误消息,不包含堆栈
%q //输出的错误消息用引号括起来,不包含堆栈
% v //输出错误消息和堆栈
如果上面有循环包装错误类型,则递归输出这些错误。
摘要
使用此github.com/pkg/errors错误库,您可以收集更多信息,轻松找到问题。
我们收集的这些信息不仅可以输出到控制台,还可以作为日志使用,还可以输出到相应的日志日志,以便于分析问题。
据说该库将加入Golang标准SDK。加入后,期待补充当前标准仓库中名为errors的package。
02
2022-09
17
2022-03
12
2021-11
28
2021-08
28
2021-08
28
2021-08