去error handling技术
我刚刚开始使用Go。 我的代码开始有很多这样的:
if err != nil { //handle err }
或这个
if err := rows.Scan(&some_column); err != nil { //handle err }
在Go中有没有一些很好的成语/策略/最佳实践来检查和处理错误?
编辑澄清:我不是肚子疼或者build议Go团队想出更好的东西。 我问我是否做得对,还是错过了社区提出的一些技巧。 谢谢大家。
你的代码是惯用的,在我看来这是最好的做法。 有些人肯定会不同意,但我认为这是Golang标准库所见的风格。 换句话说,Go作者以这种方式编写error handling。
在这个问题六个月后,Rob Pike写了一篇名为“ 错误就是价值 ”的博客文章。
在那里他认为,你不需要按照OP提出的方式进行编程,而是在标准库中的几个地方使用不同的模式。
当然,涉及错误值的常见语句是testing它是否为零,但是可以用错误值做无数其他事情,并且应用其他一些东西可以使程序更好,从而消除了大量的样板如果每个错误都与死记硬背检查相关,那么就会出现这种情况。
…
使用该语言来简化error handling。
但要记住:无论你做什么,总是检查你的错误!
这是一个很好的阅读。
我同意jnml的答案,他们都是惯用的代码,并添加以下内容:
你的第一个例子:
if err != nil { //handle err }
在处理多个返回值时更为习惯。 例如:
val, err := someFunc() if err != nil { //handle err } //do stuff with val
你的第二个例子是很好的速记,只处理err
值。 如果函数只返回一个error
,或者如果故意忽略error
以外的返回值,这将适用。 作为一个例子,这有时与Reader
和Writer
函数一起使用,它返回一个写入字节数的int
(有时是不必要的信息)和一个error
:
if _, err := f.Read(file); err != nil { //handle err } //do stuff with f
第二种forms被称为使用if初始化语句 。
所以就最佳实践而言,就我所知(除了使用“错误”包在需要时使用“错误”包创build新错误),您几乎涵盖了所有需要了解Go的错误!
编辑:如果你发现你真的不能没有例外生活,你可以模仿他们defer
, panic
和recover
。
我制作了一个精简的error handling库,并通过Go函数队列pipe道。
你可以在这里find它: https : //github.com/go-on/queue
它有一个紧凑和冗长的句法变体。 下面是一个短语法的例子:
import "github.com/go-on/queue/q" func SaveUser(w http.ResponseWriter, rq *http.Request) { u := &User{} err := qQ( ioutil.ReadAll, rq.Body, // read json (returns json and error) )( // qV pipes the json from the previous function call json.Unmarshal, qV, u, // unmarshal json from above (returns error) )( u.Validate, // validate the user (returns error) )( u.Save, // save the user (returns error) )( ok, w, // send the "ok" message (returns no error) ).Run() if err != nil { switch err { case *json.SyntaxError: ... } } }
请注意,由于它使用了reflection,因此性能开销很小。
此外,这不是惯用的代码,所以你会想在你自己的项目中使用它,或者如果你的团队同意使用它。
处理golang和其他语言中的错误的“策略”是不断地在调用堆栈中传播错误,直到在调用堆栈中足够高以处理该错误为止。 如果您尝试过早地处理该错误,那么您可能最终会重复代码。 如果你处理得太晚,那么你会在代码中破坏一些东西。 Golang使这个过程变得非常简单,因为它能够非常清楚地处理给定位置的错误还是传播错误。
如果你会忽略这个错误,一个简单的_将会很清楚地揭示这个事实。 如果您正在处理它,那么您正在处理的错误的确切情况是清楚的,因为您将在if语句中检查它。
就像上面说的人一样,一个错误实际上只是一个正常值。 这样对待它。
你可以清理你的error handling代码,类似的错误(因为错误是你必须小心的值),并写入一个函数,你传入的错误来处理错误。 那么每次都不用写“if err = nil {}”。 再次,这只会导致清理代码,但我不认为这是做事的惯用方式。
再次,只因为你可以不意味着你应该 。
大多数在行业中,遵循golang文档中提到的标准规则error handling和Go 。 它也有助于项目的文档生成。
goerr允许用function来处理错误
package main import "github.com/goerr/goerr" import "fmt" func ok(err error) { if err != nil { goerr.Return(err) // returns the error from do_somethingN() to main() // sequence() is terminated } } func sequence() error { ok(do_something1()) ok(do_something2()) ok(do_something3()) return nil /// 1,2,3 succeeded } func do_something1() error { return nil } func do_something2() error { return fmt.Errorf("2") } func do_something3() error { fmt.Println("DOING 3") return nil } func main() { err_do_something := goerr.OR1(sequence) // handle errors fmt.Println(err_do_something) }
如果你想精确地控制错误,这可能不是解决scheme,但是对于我来说,大多数时候,任何错误都是阻碍。
所以,我用function来代替。
func Err(err error) { if err!=nil { fmt.Println("Oops", err) os.Exit(1) } } fi, err := os.Open("mmm.txt") Err(err)