Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 1 | # Errors |
| 2 | |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 3 | Errors are indicated by returning an `error` as an additional return value from a function. A `nil` value means that there was no error. |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 4 | |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 5 | ` error `s can be turned into strings by calling `Error`, their only method. You can create an error from a string by calling `errors.New`: |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 6 | |
Ondrej Fabry | f296663 | 2018-06-07 14:55:48 +0200 | [diff] [blame] | 7 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 8 | if failure { |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 9 | return errors.New("inverse tachyon pulse failed") |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 10 | } |
| 11 | ``` |
| 12 | |
Nika Jones | a0668e2 | 2018-10-09 01:12:43 -0700 | [diff] [blame] | 13 | or by using `fmt.Errorf`: |
| 14 | |
| 15 | ```go |
| 16 | if failure { |
| 17 | return fmt.Errorf("inverse tachyon pulse failed") |
| 18 | } |
| 19 | ``` |
| 20 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 21 | Error strings should not start with a capital letter because they'll often be prefixed before printing: |
| 22 | |
Ondrej Fabry | f296663 | 2018-06-07 14:55:48 +0200 | [diff] [blame] | 23 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 24 | err := TryInverseTachyonPulse() |
| 25 | if err != nil { |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 26 | fmt.Printf("failed to solve problem: %s\n", err) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 27 | } |
| 28 | ``` |
| 29 | |
| 30 | If you expect calling code to be able to handle an error, you can distinguish classes of errors either by returning special values, or new types. You only need to distinguish differences that the calling code could be expected to handle in this way as the string allows one to communicate the details of the error. |
| 31 | |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 32 | `io.EOF` is a special value that signals the end of a stream. You can compare error values directly against io.EOF. |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 33 | |
| 34 | If you want to carry extra data with the error, you can use a new type: |
| 35 | |
Ondrej Fabry | f296663 | 2018-06-07 14:55:48 +0200 | [diff] [blame] | 36 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 37 | type ParseError struct { |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 38 | Line, Col int |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | func (p ParseError) Error() string { |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 42 | return fmt.Sprintf("parse error on line %d, column %d", p.Line, p.Col) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 43 | } |
| 44 | ``` |
| 45 | |
Nika Jones | a0668e2 | 2018-10-09 01:12:43 -0700 | [diff] [blame] | 46 | If you want to create a constant string error, you can use a named type string: |
| 47 | |
| 48 | ```go |
| 49 | type errorConst string |
| 50 | |
| 51 | const ErrTooManyErrors errorConst = "too many errors found." |
| 52 | ``` |
| 53 | |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 54 | Calling code would test for a special type of `error` by using a type switch: |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 55 | |
Ondrej Fabry | f296663 | 2018-06-07 14:55:48 +0200 | [diff] [blame] | 56 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 57 | switch err := err.(type) { |
| 58 | case ParseError: |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 59 | PrintParseError(err) |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 60 | } |
| 61 | ``` |
| 62 | |
| 63 | ## Naming |
| 64 | |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 65 | Error types end in `"Error"` and error variables start with `"Err"`: |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 66 | |
Ondrej Fabry | f296663 | 2018-06-07 14:55:48 +0200 | [diff] [blame] | 67 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 68 | package somepkg |
| 69 | |
| 70 | // ParseError is type of error returned when there's a parsing problem. |
| 71 | type ParseError struct { |
| 72 | Line, Col int |
| 73 | } |
| 74 | |
| 75 | var ErrBadAction = errors.New("somepkg: a bad action was performed") |
| 76 | |
| 77 | // ----- |
| 78 | |
| 79 | package foo |
| 80 | |
| 81 | func foo() { |
| 82 | res, err := somepkgAction() |
| 83 | if err != nil { |
| 84 | if err == somepkg.ErrBadAction { |
| 85 | } |
| 86 | if pe, ok := err.(*somepkg.ParseError); ok { |
| 87 | line, col := pe.Line, pe.Col |
| 88 | // .... |
| 89 | } |
| 90 | } |
| 91 | } |
| 92 | ``` |
| 93 | |
| 94 | ## References |
| 95 | |
| 96 | * Errors (specification): http://golang.org/ref/spec#Errors |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 97 | * Package `errors`: http://golang.org/pkg/errors/ |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 98 | * Type switches: http://golang.org/doc/go_spec.html#TypeSwitchStmt |