Errors

In Go it’s idiomatic to communicate errors via an explicit, separate return value. This contrasts with the exceptions used in languages like Java and Ruby and the overloaded single result / error value sometimes used in C. Go’s approach makes it easy to see which functions return errors and to handle them using the same language constructs employed for any other, non-error tasks.

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. // By convention, errors are the last return value and have type error,
  7. // a built-in interface.
  8. func f1(arg int) (int, error) {
  9. if arg == 42 {
  10. // errors.New constructs a basic error value with the given error message.
  11. return -1, errors.New("can't work with 42")
  12. }
  13. // A nil value in the error position indicates that there was no error.
  14. return arg + 3, nil
  15. }
  16. // It’s possible to use custom types as errors by implementing the Error() method
  17. // on them. Here’s a variant on the example above that uses a custom type to
  18. // explicitly represent an argument error.
  19. type argError struct {
  20. arg int
  21. prob string
  22. }
  23. func (e *argError) Error() string {
  24. return fmt.Sprintf("%d - %s", e.arg, e.prob)
  25. }
  26. func f2(arg int) (int, error) {
  27. if arg == 42 {
  28. // In this case we use &argError syntax to build a new struct,
  29. // supplying values for the two fields arg and prob.
  30. return -1, &argError{arg, "can't work with it"}
  31. }
  32. return arg + 3, nil
  33. }
  34. func main() {
  35. // The two loops below test out each of our error-returning functions.
  36. // Note that the use of an inline error check on the if line is a common idiom in Go code.
  37. for _, i := range []int{7, 42} {
  38. if r, e := f1(i); e != nil {
  39. fmt.Println("f1 failed:", e)
  40. } else {
  41. fmt.Println("f1 worked:", r)
  42. }
  43. }
  44. for _, i := range []int{7, 42} {
  45. if r, e := f2(i); e != nil {
  46. fmt.Println("f2 failed:", e)
  47. } else {
  48. fmt.Println("f2 worked:", r)
  49. }
  50. }
  51. // If you want to programmatically use the data in a custom error,
  52. // you’ll need to get the error as an instance of the custom error type
  53. // via type assertion.
  54. _, e := f2(42)
  55. if ae, ok := e.(*argError); ok {
  56. fmt.Println(ae.arg)
  57. fmt.Println(ae.prob)
  58. }
  59. }
  1. f1 worked: 10
  2. f1 failed: can't work with 42
  3. f2 worked: 10
  4. f2 failed: 42 - can't work with it
  5. 42
  6. can't work with it