我刚开始接触Go语言。我的代码中开始出现很多这种情况:
if err != nil {
//handle err
}
或者这个
if err := rows.Scan(&some_column); err != nil {
//handle err
}
在Go语言中,有一些好的成语/策略/最佳实践来检查和处理错误吗?
编辑以澄清:我不是在抱怨或建议Go团队提出更好的方法。我想知道我是否做得对,或者是否错过了社区已经找到的某些技巧。谢谢大家。
我刚开始接触Go语言。我的代码中开始出现很多这种情况:
if err != nil {
//handle err
}
或者这个
if err := rows.Scan(&some_column); err != nil {
//handle err
}
在Go语言中,有一些好的成语/策略/最佳实践来检查和处理错误吗?
编辑以澄清:我不是在抱怨或建议Go团队提出更好的方法。我想知道我是否做得对,或者是否错过了社区已经找到的某些技巧。谢谢大家。
你的代码风格符合惯例,在我看来是最佳实践。当然也有人持不同意见,但我会辩称这种风格在 Golang标准库 中随处可见。换句话说,Go的作者们以这种方式编写错误处理。
我同意jnml的答案,他们都是惯用代码。此外,我还要补充以下内容:
你的第一个例子:
if err != nil {
//handle err
}
在处理多个返回值时,使用"更为惯用"。例如:
val, err := someFunc()
if err != nil {
//handle err
}
//do stuff with val
如果函数只返回一个error
,或者您有意忽略除error
之外的返回值,那么您的第二个示例是一种很好的简写方式。例如,这在返回写入的字节数(有时是不必要的信息)和error
的Reader
和Writer
函数中有时会使用:
if _, err := f.Read(file); err != nil {
//handle err
}
//do stuff with f
第二种形式被称为使用if初始化声明。
因此,就最佳实践而言,据我所知(除了在需要创建新错误时使用"errors"包之外),您已经覆盖了Go中有关错误的几乎所有知识!
编辑:如果您真的无法离开异常,可以使用defer
、panic
和recover
来模仿它们。
func f() error {
handle err { fmt.Println(err); return err }
check mayFail()
check canFail()
}
更新:初稿设计受到了很多批评,因此我起草了考虑Go 2错误处理的要求,列出了可能的解决方案菜单。
import "github.com/go-on/queue/q"
func SaveUser(w http.ResponseWriter, rq *http.Request) {
u := &User{}
err := q.Q(
ioutil.ReadAll, rq.Body, // read json (returns json and error)
)(
// q.V pipes the json from the previous function call
json.Unmarshal, q.V, 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:
...
}
}
}
type HTTPAdapter struct {
Error *common.AppError
}
func (adapter *HTTPAdapter) ReadUUID(r *http.Request, param string, possibleError int) uuid.UUID {
requestUUID := uuid.Parse(mux.Vars(r)[param])
if requestUUID == nil {
adapter.Error = common.NewAppError(fmt.Errorf("parameter %v is not valid", param),
possibleError, http.StatusBadRequest)
}
return requestUUID
}
adapter := &httphelper.HTTPAdapter{}
viewingID := adapter.ReadUUID(r, "viewingID", common.ErrorWhenReadingViewingID)
messageID := adapter.ReadUUID(r, "messageID", common.ErrorWhenReadingMessadeID)
if adapter.Error != nil {
return nil, adapter.Error
}
这不是一劳永逸的解决方案,缺点是如果出现多个错误,您只能获取最后一个错误。
但在这种情况下,重复性和风险较低,因此我只需获取最后可能出现的错误。
您可以为类似的错误清理错误处理代码(因为错误是值,所以在这里必须小心),并编写一个函数,您将传递错误并处理该错误。然后您就不必每次都编写“if err!= nil {}”了。再次强调,这只会使代码更加简洁,但我认为这不是惯用的做法。
再次强调,仅仅因为您可以这样做,并不意味着您应该这样做。
goerr 允许使用函数处理错误
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)
}