This page looks best with JavaScript enabled

Go errors

 ·  πŸŽƒ kr0m

In Go, there’s no special mechanism for directly binding methods to error types. Errors in Go are simply values that fulfill the error interface, which has a single method, Error() string. Therefore, any type that implements this method can be used as an error in Go.


If you are new to the world of Go, I recommend the following previous articles:


The first thing we need to know is that in Go, the error value returned by a function should always be the last one, for example:

func f1(arg int) (int, error) {
    if arg == 42 {
        return -1, errors.New("can't work with 42")
    }
    return arg + 3, nil
}

We can easily create custom errors by simply implementing the error interface, which has a single method, Error() string. Therefore, we create a structure with the required fields. This structure will be associated with the Error() function due to Go’s methods . Next, in the function f2, we create an object of type argError, passing the expected values ​​for the structure as parameters:

type argError struct {
    arg  int
    prob string
}

func (e *argError) Error() string {
    return fmt.Sprintf("%d - %s", e.arg, e.prob)
}

func f2(arg int) (int, error) {
    if arg == 42 {
        return -1, &argError{arg, "can't work with it"}
    }
    return arg + 3, nil
}

If we don’t want to display the error exactly as it comes from our Error function, we can capture the error and access each of the data fields in the structure. In this case, the error is captured in the variable e, and then we dump the fields into the variable fieldsStructure, which has the fields defined in the argError structure. The second return parameter indicates whether the dumping was successful or not. In the case of success, we print the data:

    _, e := f2(42)
    if fieldsStructure, ok := e.(*argError); ok {
        fmt.Println(fieldsStructure.arg)
        fmt.Println(fieldsStructure.prob)
    }

Let’s see the complete example:

vi customError.go

package main

import (
    "errors"
    "fmt"
)

func f1(arg int) (int, error) {
    if arg == 42 {
        return -1, errors.New("can't work with 42")
    }
    return arg + 3, nil
}

type argError struct {
    arg  int
    prob string
}

func (e *argError) Error() string {
    return fmt.Sprintf("%d - %s", e.arg, e.prob)
}

func f2(arg int) (int, error) {
    if arg == 42 {
        return -1, &argError{arg, "can't work with it"}
    }
    return arg + 3, nil
}

func main() {
    for _, i := range []int{7, 42} {
        if r, e := f1(i); e != nil {
            fmt.Println("f1 failed:", e)
        } else {
            fmt.Println("f1 worked:", r)
        }
    }
    for _, i := range []int{7, 42} {
        if r, e := f2(i); e != nil {
            fmt.Println("f2 failed:", e)
        } else {
            fmt.Println("f2 worked:", r)
        }
    }
    _, e := f2(42)
    if fieldsStructure, ok := e.(*argError); ok {
        fmt.Println(fieldsStructure.arg)
        fmt.Println(fieldsStructure.prob)
    }
}

We execute the code:

go run customError.go

f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it
If you liked the article, you can treat me to a RedBull here