package main import ( "errors" "fmt" ) // a function that can fail, so it returns an error as the second return value func f(arg int) (int, error) { if arg == 42 { // in case of an error, return the zero value for the result and a non-nil error return 0, errors.New("can't work with 42") } // simply return the result and a nil error in the success case return arg + 3, nil } // define some errors to use in makeTea var ErrOutOfTea = fmt.Errorf("no more tea available") var ErrPower = fmt.Errorf("can't boil water") // a function that can fail in multiple ways, so it returns an error as the second return value func makeTea(arg int) error { if arg == 2 { // return the error directly, so we can check for it later with errors.Is return ErrOutOfTea } else if arg == 4 { // use %w to wrap the error, so we can check for it later with errors.Is return fmt.Errorf("making tea: %w", ErrPower) } return nil } func main() { for _, i := range []int{7, 42} { //typical pattern for checking errors in Go: if the error is not nil, handle it and return or continue; otherwise, use the result if r, e := f(i); e != nil { fmt.Println("f failed:", e) } else { fmt.Println("f worked:", r) } } for i := range 5 { if err := makeTea(i); err != nil { // use errors.Is to check for specific errors, even if they are wrapped if errors.Is(err, ErrOutOfTea) { fmt.Println("We should buy new tea!") } else if errors.Is(err, ErrPower) { // this error is wrapped, but errors.Is can still check for it fmt.Println("Now it is dark.") } else { fmt.Printf("unknown error: %s\n", err) } continue } fmt.Println("Tea is ready!") } }