2 回答
TA贡献1796条经验 获得超7个赞
编辑:这个答案早于 Go 1.13,它提供了与所介绍的技术类似的东西。请查看Go 博客:处理 Go 1.13 中的错误。
您应该处理错误,或者不处理错误,而是将其委托给更高级别(给调用者)。处理错误并返回它是不好的做法,就好像调用者也这样做一样,错误可能会被处理多次。
处理错误意味着检查它并根据它做出决定,这可能是您简单地记录它,但这也算作“处理”它。
如果您选择不处理而是将其委托给更高级别,那可能很好,但不要只返回您得到的错误值,因为它可能对没有上下文的调用者毫无意义。
注释错误
一个非常好的和推荐的委派方式是Annotating errors。这意味着您创建并返回一个新的错误值,但旧的错误值也包含在返回值中。包装器为包装的错误提供上下文。
没有为标注错误公共图书馆:github.com/pkg/errors; 及其godoc:errors
它基本上有 2 个功能: 1 用于包装现有错误:
func Wrap(cause error, message string) error
还有一个用于提取包装错误:
func Cause(err error) error
使用这些,您的错误处理可能如下所示:
func (o *ObjectOne) CheckValue() error {
if o.someValue == 0 {
return errors.New("Object1 illegal state: value is 0")
}
return nil
}
第二级:
func (oT *ObjectTwoHigherLevel) CheckObjectOneIsReady() error {
if err := oT.objectOne.CheckValue(); err != nil {
return errors.Wrap(err, "Object2 illegal state: Object1 is invalid")
}
return nil
}
第三级:仅调用第二级检查:
func (oTh *ObjectThreeHiggerLevel) CheckObjectTwoIsReady() error {
if err := oTh.ObjectTwoHigherLevel.CheckObjectOneIsReady(); err != nil {
return errors.Wrap(err, "Object3 illegal state: Object2 is invalid")
}
return nil
}
请注意,由于这些CheckXX()方法不处理错误,因此它们不会记录任何内容。他们正在委派带注释的错误。
如果有人使用ObjectThreeHiggerLevel决定处理错误:
o3 := &ObjectThreeHiggerLevel{}
if err := o3.CheckObjectTwoIsReady(); err != nil {
fmt.Println(err)
}
将呈现以下漂亮的输出:
Object3 illegal state: Object2 is invalid: Object2 illegal state: Object1 is invalid: Object1 illegal state: value is 0
没有多个日志的污染,并且所有细节和上下文都被保留了,因为我们使用errors.Wrap()它产生一个错误值,该错误值格式化为 a string,它递归地保留包装的错误:错误堆栈。
您可以在博客文章中阅读有关此技术的更多信息:
Dave Cheney:不要只检查错误,要优雅地处理它们
“扩展”错误
如果您喜欢更简单的事情和/或您不想与外部库发生麻烦并且您无法提取原始错误(确切的错误值,而不是您可以的错误字符串),那么您可以只需使用上下文扩展错误并返回这个新的扩展错误。
扩展错误最容易通过使用fmt.Errorf()它来完成,它允许您创建一个“漂亮”的格式化错误消息,它会返回一个类型的值,error因此您可以直接返回它。
使用fmt.Errorf(),您的错误处理可能如下所示:
func (o *ObjectOne) CheckValue() error {
if o.someValue == 0 {
return fmt.Errorf("Object1 illegal state: value is %d", o.someValue)
}
return nil
}
第二级:
func (oT *ObjectTwoHigherLevel) CheckObjectOneIsReady() error {
if err := oT.objectOne.CheckValue(); err != nil {
return fmt.Errorf("Object2 illegal state: %v", err)
}
return nil
}
第三级:仅调用第二级检查:
func (oTh *ObjectThreeHiggerLevel) CheckObjectTwoIsReady() error {
if err := oTh.ObjectTwoHigherLevel.CheckObjectOneIsReady(); err != nil {
return fmt.Errorf("Object3 illegal state: %v", err)
}
return nil
}
ObjectThreeHiggerLevel如果它决定“处理”它,将显示以下错误消息:
o3 := &ObjectThreeHiggerLevel{}
if err := o3.CheckObjectTwoIsReady(); err != nil {
fmt.Println(err)
}
将呈现以下漂亮的输出:
Object3 illegal state: Object2 illegal state: Object1 illegal state: value is 0
请务必阅读博文:错误处理和 Go
TA贡献1801条经验 获得超16个赞
有各种库将堆栈跟踪嵌入到 Go 错误中。只需使用其中之一创建错误,它就会冒出完整的堆栈上下文,您可以稍后检查或记录。
一个这样的图书馆:
https://github.com/go-errors/errors
还有一些我忘记了。
- 2 回答
- 0 关注
- 179 浏览
添加回答
举报