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. |
|
package main
|
|
import "errors"
import "fmt"
|
|
By convention, errors are the last return value and
have type |
func f1(arg int) (int, error) {
if arg == 42 {
|
|
return -1, errors.New("can't work with 42")
|
}
|
|
A nil value in the error position indicates that there was no error. |
return arg + 3, nil
}
|
It’s possible to use custom types as |
type argError struct {
arg int
prob string
}
|
func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
|
|
func f2(arg int) (int, error) {
if arg == 42 {
|
|
In this case we use |
return -1, &argError{arg, "can't work with it"}
}
return arg + 3, nil
}
|
func main() {
|
|
The two loops below test out each of our
error-returning functions. Note that the use of an
inline error check on the |
for _, i := range []int{7, 42} {
if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e)
} else {
fmt.Println("f1 worked:", r)
}
}
for _, i := range []int{7, 42} {
if r, e := f2(i); e != nil {
fmt.Println("f2 failed:", e)
} else {
fmt.Println("f2 worked:", r)
}
}
|
If you want to programmatically use the data in a custom error, you’ll need to get the error as an instance of the custom error type via type assertion. |
_, e := f2(42)
if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
}
|
$ go run errors.go
f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it
|
|
See this great post on the Go blog for more on error handling. |
Next example: Goroutines.