【问题标题】:Acceptable Golang idiomatic nested error handling?可接受的 Golang 惯用嵌套错误处理?
【发布时间】:2017-01-31 01:54:18
【问题描述】:

我最近接触了 Go,看到很多关于如何进行错误处理的讨论。

我看到的布局如下:

err := DoSomething()
if err != nil {
   //handle
}
// continue

经常在管理 amqp 连接时,我的条件是只有在错误为 nil 时才想继续,因为那时我需要对连接做一些事情:

c, err := Connect()
if err != nil {
   return nil, err
}
s,err := c.RegisterSomethingOnConnection()
if err != nil {
   return nil, err
}
val, err := s.DoSomething()
return val, err

如您所见,如果从Connect() 返回的错误为零,我只想运行c.RegisterSomethingOnConnection 行。

但是,由于提前返回,我不喜欢上述内容。提前返回让我感到不舒服,因为从长远来看,它会损害可读性并且会模糊函数退出的确切时间。到目前为止,我的解决方案是执行以下操作:

var err error
var val ReturnType

c,err := Connect()
if err == nil {
    s,err := c.RegisterSomethingOnConnection()
    if err == nil {
       val,err = s.DoSomething()
    }
}
return val,err

我喜欢这样做有两个原因。首先,它防止返回 nil。其次,我发现它使代码更易于维护,因为您可以在返回之前轻松添加添加功能(即日志记录),并且不会让某些路径由于提前返回而错过添加的功能。

我所做的是可接受的惯用围棋,还是我只需要克服我对早期回报的厌恶并遵循该模式?

【问题讨论】:

标签: go idioms


【解决方案1】:

Go Prover 之一是:

不要只检查错误,要优雅地处理它们

我建议您阅读 Dave Cheney 的 post

我把重点放在这里:

“处理错误没有单一的方法。相反,我认为 Go 的错误处理可以分为三个核心策略”

  • 前哨错误:

if err == ErrSomething { … }

“使用标记值是最不灵活的错误处理策略,因为调用者必须使用相等运算符将结果与预先声明的值进行比较。当您想要提供更多上下文时,这会出现问题,因为返回不同的错误会破坏相等性检查。”

  • 错误类型

if err, ok := err.(SomeType); ok { … }

“错误类型是您创建的实现错误接口的类型。”

  • 不透明错误

x, err := bar.Foo() if err != nil { return err } // use x

“我将这种风格称为不透明错误处理,因为当你知道发生了错误时,你没有能力看到错误的内部。作为调用者,你对操作结果的了解只有它起作用了,或者没有。”

....阅读所有帖子。

我认为错误处理的重要方面是不要只是检查错误,而是要优雅地处理它们,我希望这可以帮助你。

【讨论】:

  • 谢谢,这篇文章很有帮助。如果我理解正确,如果你用额外的上下文包装了它并且只将它记录在一个地方,那么返回一个错误是可以的,对吗?
  • @Fuzzerker 我认为是正确的,错误是针对人类而不是针对代码的。
  • @Fuzzerker 我喜欢这种方式,return fmt.Errorf("authenticate failed: %v", err)不要错过出错的地方。
【解决方案2】:

Go. Best practice to handle error from multiple abstract level:

您应该处理一个错误,或者不处理它而是将它委托给 更高级别(对调用者)。处理错误并返回它是 不好的做法,就好像调用者也这样做一样,错误可能会得到 处理了几次。

请参阅:
Errors are Values,作者:Rob Pike。

Go Error Handling Techniques


你可以简化它:

if err := datastore.Get(c, key, record); err != nil {

简化重复性错误处理:

在 Go 中,错误处理很重要。语言的设计和 约定鼓励您明确检查错误 发生(不同于其他语言的投掷习惯 异常,有时会捕获它们)。在某些情况下,这使得 Go 代码冗长,但幸运的是,您可以使用一些技术 尽量减少重复的错误处理。

考虑一个具有 HTTP 处理程序的 App Engine 应用程序,该处理程序检索 来自数据存储的记录并使用模板对其进行格式化。

func init() {
    http.HandleFunc("/view", viewRecord)
}

func viewRecord(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    key := datastore.NewKey(c, "Record", r.FormValue("id"), 0, nil)
    record := new(Record)
    if err := datastore.Get(c, key, record); err != nil {
        http.Error(w, err.Error(), 500)
        return
    }
    if err := viewTemplate.Execute(w, record); err != nil {
        http.Error(w, err.Error(), 500)
    }
}

见:https://blog.golang.org/error-handling-and-go

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    • 2017-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    • 1970-01-01
    相关资源
    最近更新 更多