Returning an error
suggest changeTo 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
.
To put it differently:
var err1 error
var err2 error = nil
var err3 error = (*CustomError)(nil)
if err1 == nil && err2 == nil {
fmt.Printf("unitialized interface value and inteface value assigned nil are both zero values of interface type and therefore equal to 'nil'\n")
}
if err3 != nil {
fmt.Printf("interface value assigned to a struct type whose value is nil is not zero value of interface type and therefore not equal to 'nil'\n")
}