gpt4 book ai didi

go - 处理来自多个抽象级别的错误的最佳实践

转载 作者:IT王子 更新时间:2023-10-29 01:12:56 28 4
gpt4 key购买 nike

我想知道在 go 中处理多级抽象错误的最佳方法是什么。每次如果我必须为程序添加一个新的层次抽象,我就被迫将错误代码从较低的层次转移到较高的层次。因此,日志文件中存在重复通信,否则我必须记住删除低级别的通信表单并将其转移到更高级别。下面简单举例。我跳过了创建每个对象到更简短的代码,但我想你理解我的问题

type ObjectOne struct{
someValue int
}

func (o* ObjectOne)CheckValue()error{
if o.someValue == 0 {
SomeLogger.Printf("Value is 0 error program") // communicate form first level abstraction to logger
return errors.New("Internal value in object is 0")
}
return nil
}

type ObjectTwoHigherLevel struct{
objectOne ObjectOne
}

func (oT* ObjectTwoHigherLevel)CheckObjectOneIsReady() error{
if err := oT.objectOne.CheckValue() ; err != nil{
SomeLogger.Printf("Value in objectOne is not correct for objectTwo %s" , err) // second communicate
return err
}
return nil
}

type ObjectThreeHiggerLevel struct{
oT ObjectTwoHigherLevel
}

func (oTh* ObjectThreeHiggerLevel)CheckObjectTwoIsReady()error{
if err := oTh.oT.CheckObjectOneIsReady() ; err != nil{
SomeLogger.Printf("Value in objectTwo is not correct for objectThree %s" , err)
return err
}
return nil
}

在日志文件中我得到了重复的帖子

Value is 0 error program 
Value in objectOne is not correct for objectTwo Internal value in object is 0
Value in objectTwo is not correct for objectThree Internal value in object is 0

反过来,如果我只将一些 err 传输到更高级别而没有额外的日志,我会丢失每个级别发生的信息。

这个怎么解决?私有(private)副本如何通信?或者我的方式是唯一的好办法?

如果我创建了一些对象来在一些抽象级别上在数据库中搜索某些内容,那么问题就更令人沮丧了,然后我在 logFile 中也从这个相同的任务中得到几行。

最佳答案

编辑: 这个答案早于 Go 1.13,它提供了与所呈现的技术类似的东西。请查看The Go Blog: Working with Errors in Go 1.13 .


您应该处理错误,或者不处理错误而是将其委托(delegate)给更高级别(调用者)。处理错误并将其返回是不好的做法,就好像调用者也做同样的事情一样,错误可能会被处理多次。

处理错误意味着检查它并据此做出决定,这可能是您简单地记录它,但这也算作“处理”它。

如果您选择不处理而是将其委托(delegate)给更高级别,那可能完全没问题,但不要只返回您得到的错误值,因为它可能对没有上下文的调用者毫无意义。

注释错误

注释错误是一种非常好的和推荐的委派方式。这意味着您创建并返回了一个 错误值,但旧值也包含在返回值中。包装器为包装错误提供上下文。

有一个用于注释错误的公共(public)库:github.com/pkg/errors ;及其 godoc:errors

它基本上有 2 个功能:1 个用于 wrapping现有错误:

func Wrap(cause error, message string) error

还有一个用于 extracting包装错误:

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() 方法不处理错误,因此它们不会记录任何内容。他们委托(delegate)带注释的错误。

如果有人使用 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() 产生一个错误值,该错误值被格式化为一个 string 以递归方式保留包装的错误:错误堆栈

您可以在博文中阅读有关此技术的更多信息:

Dave Cheney: Don’t just check errors, handle them gracefully

“扩展”错误

如果您喜欢更简单的事情和/或您不想与外部库打交道,并且您可以接受无法提取原始错误(确切的错误,而不是error string,你可以),那么你可以简单地使用上下文扩展错误并返回这个新的扩展错误。

使用 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

请务必阅读博文:Error handling and Go

关于go - 处理来自多个抽象级别的错误的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37346694/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com