【问题标题】:Whats the correct Go way to do handle errors什么是正确的 Go 方法来处理错误
【发布时间】:2014-07-25 05:37:36
【问题描述】:

这似乎有点愚蠢,肯定有更好的方法吗?

err = SendMessageAndWait(db, "this is a test")
if err != nil {
    fmt.Println("Error sending message", err)
    return
}
err = DoSomething(db, "this is a test")
if err != nil {
    fmt.Println("Error sending message", err)
    return
}
err = CheckSomething(db, "this is another test")
if err != nil {
    fmt.Println("Error sending message", err)
    return
}
err = SendMessageAndWait(db, "this is a third test")
if err != nil {
    fmt.Println("Error sending message", err)
    return
}
... x10 ...

更新: 作为记录,从我写这篇文章的 5 年开始,我现在确信这是一种完全足够,甚至可能更好的方式来清楚地处理错误。虽然不是说它漂亮。

【问题讨论】:

  • 在以下链接中有一个关于 GO 错误处理的有趣讨论(以及更改它的建议):github.com/golang/go/issues/32437
  • 是的,感谢您分享此内容供其他人在此处查看。阅读该提案改变了我的观点并促使我更新了帖子。我认为没有更好的选择(我见过)。

标签: go


【解决方案1】:

遗憾的是,这就是 Go 中的方式,但是您可以通过某种方式使其更简洁:

func isError(err error, pre string) error {
    if err != nil {
        log.Printf("%v: %v", pre, err)
    }
    return err
}

func isErrorBool(err error, pre string) (b bool) {
    if err != nil {
        log.Printf("%v: %v", pre, err)
        b = true
    }
    return
}

func checkSomething() error {
    return nil
}

func main() {
    if err := isError(checkSomething(), "something failed"); err != nil {
        return /* err */
    }

    //if you don't want to return the error, just check it and die.
    if isErrorBool(checkSomething(), "something else failed") { 
        return
    }
}

【讨论】:

    【解决方案2】:

    我不会只打印一个错误而不返回任何内容:我的想法是对错误采取行动返回它(如果没有采取决定性的行动,就像一个简单的日志)。
    就应用程序的其余部分而言,简单地调用 return 就像完全忽略错误一样。

    请参阅“Best Practices for Errors in Go”,其中包括以下建议:

    预定义错误

    鉴于一小部分错误,处理此问题的最佳方法是在包级别公开预定义每个错误。

    提供信息

    自定义错误类型是解决此问题的最佳方法。 Go 的隐式接口使创建一个简单的接口

    提供堆栈跟踪

    errgo 包提供了将错误包装到另一个记录错误发生位置的功能。

    (与dropbox/godropbox/errors/errors.go的功能相同)

    【讨论】:

    • 谢谢,这是所有重要信息。该代码旨在作为演示问题的示例,而不是完全惯用的代码。不过还是谢谢。
    【解决方案3】:

    在 Go 中,始终检查错误。例如,

    package main
    
    import "fmt"
    
    func doStuff() error {
        err := SendMessageAndWait(db, "this is a test")
        if err != nil {
            return err
        }
        err = DoSomething(db, "this is a test")
        if err != nil {
            return err
        }
        err = CheckSomething(db, "this is another test")
        if err != nil {
            return err
        }
        err = SendMessageAndWait(db, "this is a third test")
        if err != nil {
            return err
        }
        return nil
    }
    
    func main() {
        err := doStuff()
        if err != nil {
            fmt.Println("Error sending message", err)
        }
    }
    

    【讨论】:

    • 它看起来仍然很笨重,err if 语句在某些功能上必须存在 20-30 次,但这是一个改进(:
    • 如果您的函数有 20-30 次调用其他函数,请考虑拆分。
    【解决方案4】:

    鉴于您缺乏上下文,我只能假设您是从 func main() 返回的。

    http://play.golang.org/p/pgcwMb647A

    package main
    
    import (
      "fmt"
      "log"
      "errors"
    )
    
    func foo(x int) error {
      if x == 3 {
        return errors.New("x == 3")
      }
      fmt.Println(x)
      return nil
    }
    
    func main() {
      check := func(err error) {
        if err != nil {
          log.Fatal(err)
        }
      }
    
      check(foo(1))
      check(foo(2))
      check(foo(3))
      check(foo(4))
    }
    

    一般来说,显式处理是可行的方法,但您可以根据上下文执行多种操作。

    【讨论】:

      【解决方案5】:

      冒着把它变成代码高尔夫的风险,Go 支持带有赋值的单行 if 语句:

      if err := SendMessageAndWait(db, "this is a test"); err != nil {
          return err
      }
      

      缺点是所有分配的返回值都在相应的if/else if/else 块的范围内,所以如果你真的需要在那个块之外有一个不同的返回值,你必须使用更接近的东西PeterSO 的回答。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-02
        • 2017-09-20
        • 2021-12-16
        • 2018-09-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多