As opposed to other languages like Python and JavaScript that use a try-catch approach to error handling, Go encourages us to return a separate value that will indicate that the code did not perform in an ideal manner - an error.
This way of handling errors ensures that dealing with errors are part of the normal execution flow of the code, instead of having a structure that can be completely left out, as is the case of a try-catch.
Convention
It is customary to return the error as the last value from a function, with the return type being error:
package main
import (
"errors"
"fmt"
)
func Div(a, b float64) (float64, error) {
if b == 0.0 {
return 0.0, errors.New("cannot divide by zero")
}
return a / b, nil
}
func main() {
numbers := []int{3, 2, 0, -4, 5, -2}
for _, f := range numbers {
result, err := Div(4.0, float64(f))
if err != nil {
fmt.Printf("error: %v\n", err)
} else {
fmt.Printf("4/%d = %f\n", f, result)
}
}
}
The function errors.New() is used to define a new error with a desired error message. We can use the fmt.Errorf function to define errors as variables in our code:
package main
import (
"fmt"
)
var ErrNoZeroDivision = fmt.Errorf("cannot divide by zero")
func Div(a, b float64) (float64, error) {
if b == 0.0 {
return 0.0, ErrNoZeroDivision
}
return a / b, nil
}
func main() {
numbers := []int{3, 2, 0, -4, 5, -2}
for _, f := range numbers {
result, err := Div(4.0, float64(f))
if err != nil {
fmt.Printf("error: %v\n", err)
} else {
fmt.Printf("4/%d = %f\n", f, result)
}
}
}
Inline checking
We can check errors inline by separating the lines using a semi-colon:
package main
import (
"fmt"
)
var ErrNoZeroDivision = fmt.Errorf("cannot divide by zero")
func Div(a, b float64) (float64, error) {
if b == 0.0 {
return 0.0, ErrNoZeroDivision
}
return a / b, nil
}
func main() {
numbers := []int{3, 2, 0, -4, 5, -2}
for _, f := range numbers {
if result, err := Div(4.0, float64(f)); err != nil {
fmt.Printf("error: %v\n", err)
} else {
fmt.Printf("4/%d = %f\n", f, result)
}
}
}
Our code can look more compact using this technique.
Custom errors
Any custom type can be used as an error as long as it implements the Error() method.