$Id: 123

$SOId: 2707

To indicate a failure, return a value of error type.

To indicate no error, return nil.

// somewhat inefficient way of appending a string at the end of a file
func appendToFile(path string, s string) error {
	d, err := ioutil.ReadFile(path)
  if err != nil {
		return err
  }
	d = append(d, []byte(s)...)
  return ioutil.WriteFile(path, d, 0644)
}

If the function also returns one or more values, error should be the last returned value:

func sqrt(n int) (int, error) {
	if n < 0 {
		return 0, fmt.Errorf("n should be >= 0, is %d", n)
	}
	return n*n, nil
}

Pitfalls

If you're using custom error types, don't return underlying type, always return error type.,

type CustomError struct {
}

func (e *CustomError) Error() string {
	return "this is a custom error"
}

func returnsCustomError(pleaseFail bool) *CustomError {
	if pleaseFail {
		return &CustomError{}
	}
	return nil
}

func caller() {
	var err error
	if err == nil {
		fmt.Printf("err is nil, as expected\\n");
  }
	err = returnsCustomError(false))
	if err != nil {
		fmt.Printf("returnCustomError() failed with '%s'\\n", err)
  }
}

Unexpectedly it looks like returnsCustomError() returned an error even though it returned nil.

This is a variant of nil interface pitfall.

#note link to that chapter

Uninitialized err value is nil because it's the zero value of interface types.

returnsCustomError() returns nil value of CustomError struct.

This nil value is assigned to err variable. This is equivalent to:

var err error
err = (*CustomError)(nil)

At this point err is no longer equal to zero value of interface type. It's value is *CustomError whose value is nil.

Therefore err no longer equals to nil.