๐ŸŽ“ A1Learner
๐Ÿ”
0 of 34 lessons completed

Go The Error Interface

The error type is an interface with one method named Error. That method returns the problem as a string.

An error value starts as nil

A variable of the error type starts as nil. The code then stores an error built with errors.New.

package main

import (
	"errors"
	"fmt"
)

func main() {
	var err error
	fmt.Println(err == nil)
	err = errors.New("disk full")
	fmt.Println(err)
}

A custom error from a function

LimitError stores the limit and the value that broke it. Its Error method returns a fixed message.

package main

import "fmt"

type LimitError struct {
	Limit int
	Value int
}

func (e LimitError) Error() string {
	return "value is over the limit"
}

func checkValue(v int) error {
	if v > 10 {
		return LimitError{Limit: 10, Value: v}
	}
	return nil
}

func main() {
	err := checkValue(14)
	fmt.Println(err)
}

Value receivers and pointer receivers

EmptyError has a value receiver on Error. RangeError has a pointer receiver on Error. The prints show a value and a pointer for the first type, and a pointer for the second type.

package main

import "fmt"

type EmptyError struct{}

func (e EmptyError) Error() string {
	return "value is empty"
}

type RangeError struct{}

func (e *RangeError) Error() string {
	return "value is out of range"
}

func main() {
	var first error = EmptyError{}
	var second error = &EmptyError{}
	var third error = &RangeError{}
	fmt.Println(first)
	fmt.Println(second)
	fmt.Println(third)
}

Field values inside the message

fmt.Sprintf builds a string from a pattern and values. The Error method of SizeError fills %d with each stored number.

package main

import "fmt"

type SizeError struct {
	Got int
	Max int
}

func (e SizeError) Error() string {
	return fmt.Sprintf("size %d is over the max %d", e.Got, e.Max)
}

func main() {
	var err error = SizeError{Got: 25, Max: 20}
	fmt.Println(err)
}

Example

package main

import "fmt"

type FieldError struct {
	Field string
	Value int
}

func (e FieldError) Error() string {
	return fmt.Sprintf("%s value %d is not allowed", e.Field, e.Value)
}

func checkScore(score int) error {
	if score < 0 {
		return FieldError{Field: "score", Value: score}
	}
	if score > 100 {
		return FieldError{Field: "score", Value: score}
	}
	return nil
}

func main() {
	fmt.Println(checkScore(-5))
	fmt.Println(checkScore(140))
}

Key points

  • The error interface names the method Error() string.
  • A custom error type is a type that gives itself an Error method.
  • A struct error type can store fields that describe the problem.
  • The Error method can build its message from the stored fields.
  • A value receiver on Error lets a value and a pointer both serve as errors.
  • A pointer receiver on Error lets only a pointer serve as an error.

In this example, FieldError stores the name of a field and its bad value. Its Error method builds a message from both stored values. checkScore returns a FieldError when a score is below zero or above 100. Main prints the errors for -5 and 140.

Note

Printing an error value prints the string its Error method returns.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Go Playground

Exercise

Which method must a type have so its values can serve as errors?