if err != nil
Go has no exceptions. A function that can fail returns an error as its last result, and the caller checks it right there: if err != nil { … }. Newcomers find the repetition tedious; Go programmers value that every failure path is visible in the code, next to the call that can fail.
Done well, Go errors read like a story — load config: open settings.json: no such file or directory — and programs can still ask precise questions, like "was this a timeout?". Chapter 7 of *100 Go Mistakes* is all about doing it well: when to wrap, how to compare, and why you should never handle an error twice.
Errors are values
error is a tiny interface: interface { Error() string }. Make simple ones with errors.New("…") or fmt.Errorf("…", args). An error value declared once and compared by identity is a sentinel error, like io.EOF: by convention named ErrSomething.
package main
import (
"errors"
"fmt"
"strconv"
)
var ErrNegative = errors.New("negative amount")
func parseAmount(s string) (int, error) {
n, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
if n < 0 {
return 0, ErrNegative
}
return n, nil
}
func main() {
for _, s := range []string{"250", "-5", "abc"} {
n, err := parseAmount(s)
if err != nil {
fmt.Println("error:", err)
continue
}
fmt.Println("ok:", n)
}
}- Return the error as the last result; return zero values for the others.
- Handle an error once: either log it or return it, not both (mistake #52) — otherwise the same failure is reported several times.
- Don't ignore errors silently; if you really mean to, write _ = f() so readers see it was deliberate (mistake #53).