The goal of this tutorial is to provide an in-depth understanding of the 'error' interface in Go. This powerful tool allows us to handle errors in a effective and efficient manner. By the end of this tutorial, you will learn:
Prerequisites: Basic knowledge of Go language is required to fully understand the concepts and examples in this tutorial.
In Go, the 'error' interface is a built-in type used to represent an error condition, with the nil value representing no error. It is defined as follows:
type error interface {
Error() string
}
An error is nothing more than a value that represents failure. If a function or method can fail, it will return an error as its last return value. If it executes successfully, the error will be nil.
Here's a simple example:
func divide(x, y int) (int, error) {
if y == 0 {
return 0, errors.New("cannot divide by zero")
}
return x / y, nil
}
Best practices when using the 'error' interface:
Example 1:
package main
import (
"errors"
"fmt"
)
// A function that can return an error
func divide(x, y int) (int, error) {
if y == 0 {
return 0, errors.New("cannot divide by zero")
}
return x / y, nil
}
func main() {
result, err := divide(10, 2)
// Always check the error before using the result
if err != nil {
fmt.Println(err)
} else {
fmt.Println(result)
}
}
Expected output: 5
Example 2:
package main
import (
"fmt"
)
// Custom error type
type DivisionError struct {
dividend, divisor int
}
func (d *DivisionError) Error() string {
return fmt.Sprintf("cannot divide %d by %d", d.dividend, d.divisor)
}
// Function that returns a custom error
func divide(x, y int) (int, error) {
if y == 0 {
return 0, &DivisionError{x, y}
}
return x / y, nil
}
func main() {
_, err := divide(10, 0)
if err != nil {
fmt.Println(err)
}
}
Expected output: cannot divide 10 by 0
In this tutorial, you learned about the 'error' interface in Go and how to use it effectively. You learned how to return and handle errors in your programs, and how to create custom error types. The next steps would be to further practice error handling in Go and learn more advanced topics like error wrapping.
Write a function that takes a filename as argument and returns its content as a string. If the file does not exist, it should return a custom error.
Write a function that accepts a string and tries to convert it to an integer. If the string cannot be converted, it should return an error.
package main
import (
"io/ioutil"
"fmt"
)
type FileError struct {
filename string
}
func (f *FileError) Error() string {
return fmt.Sprintf("file %s does not exist", f.filename)
}
func readFile(filename string) (string, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return "", &FileError{filename}
}
return string(content), nil
}
func main() {
_, err := readFile("nonexistent.txt")
if err != nil {
fmt.Println(err)
}
}
package main
import (
"strconv"
"fmt"
)
type ConversionError struct {
original string
}
func (c *ConversionError) Error() string {
return fmt.Sprintf("%s cannot be converted to integer", c.original)
}
func convertToInt(s string) (int, error) {
i, err := strconv.Atoi(s)
if err != nil {
return 0, &ConversionError{s}
}
return i, nil
}
func main() {
_, err := convertToInt("abc")
if err != nil {
fmt.Println(err)
}
}