处理错误的正确Go方式是什么?

huangapple go评论84阅读模式
英文:

Whats the correct Go way to do handle errors

问题

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

err = SendMessageAndWait(db, "这是一个测试")
if err != nil {
    fmt.Println("发送消息时出错", err)
    return
}
err = DoSomething(db, "这是一个测试")
if err != nil {
    fmt.Println("发送消息时出错", err)
    return
}
err = CheckSomething(db, "这是另一个测试")
if err != nil {
    fmt.Println("发送消息时出错", err)
    return
}
err = SendMessageAndWait(db, "这是第三个测试")
if err != nil {
    fmt.Println("发送消息时出错", err)
    return
}
... x10 ...

更新: 值得一提的是,从我写下这段代码的5年后,我现在相信这是一种完全足够甚至更好的处理错误的方式。虽然不一定漂亮。

英文:

This seems a bit stupid, surely theres a better way?

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 ...

Update: For the record, 5 years on from when I wrote this, I am now persuaded that this is a completely sufficient, and perhaps even better, way to handle errors clearly. Not saying its pretty though.

答案1

得分: 4

很遗憾,在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 isErrorBool(checkSomething(), "something else failed") {
        return
    }
}

希望对你有帮助!

英文:

Sadly that's the way it is in Go, however in a way you can make it cleaner:

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

得分: 2

我不仅仅会打印错误并返回空值:我的想法是在处理错误的同时也返回它(如果没有采取决定性的操作,比如简单记录日志)。仅仅调用return就像完全忽略错误一样,对于应用程序的其余部分来说。

请参考“Go语言错误处理的最佳实践”,其中包括以下建议:

预定义错误

> 对于一小组错误,最好的处理方式是在包级别公开预定义每个错误。

提供信息

自定义错误类型是解决此问题的最佳方案。Go语言的隐式接口使得创建自定义错误类型变得容易。

提供堆栈跟踪

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

dropbox/godropbox/errors/errors.go也具有相同的功能)

英文:

I would not just print an error and return nothing: the idea is to act on the error and return it (if no decisive action was taken, like a simple log).
Simply calling return is like ignoring the error completely as far as the rest of the application is concerned.

See "Best Practices for Errors in Go", which includes advices as:

Predefine errors

> Given a small set of errors, the best way to handle this is to predefine each error publicly at the package level.

Provide information

custom error type is the best solution to this problem. Go's implicit interfaces make creating one easy

Provide stack traces

> package errgo provides the functionality of wrapping an error into another one that records where the error happened.

(You have the same features in dropbox/godropbox/errors/errors.go)

答案3

得分: 2

在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)
    }
}
英文:

In Go, always check for errors. For example,

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)
	}
}

答案4

得分: 2

鉴于你提供的上下文不足,我只能假设你是从func main()返回的。

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))
}

一般来说,显式处理错误是一个好的做法,但具体要做什么取决于上下文。

英文:

Given your lack of context, I can only assume you're returning from 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))
}

Generally, explicit handling is the way to go, but there's a variety of things you can do depending on the context.

答案5

得分: 2

冒着把这变成代码高尔夫的风险,Go语言支持在单行if语句中进行赋值:

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

不足之处在于,所有分配的返回值的作用域限定在相应的if/else if/else块内,所以如果你实际上需要在该块之外使用不同的返回值,你必须采用更接近PeterSO的答案。

英文:

At the risk of turning this into code golf, Go supports single line if statements with assignments in them:

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

The downside is that all return values assigned are scoped to the corresponding if/else if/else block, so if you actually need a different returned value outside that block, you have to go with something closer to PeterSO's answer.

huangapple
  • 本文由 发表于 2014年7月25日 13:37:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/24948729.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定