🐷

go 1.20 multiple errors を試してみる

2023/03/24に公開

ref: https://tip.golang.org/doc/go1.20

Wrapping multiple errors
Go 1.20 expands support for error wrapping to permit an error to wrap multiple other errors.
An error e can wrap more than one error by providing an Unwrap method that returns a []error.
The errors.Is and errors.As functions have been updated to inspect multiply wrapped errors.
The fmt.Errorf function now supports multiple occurrences of the %w format verb, which will cause it to return an error that wraps all of those error operands.

Go Playground: https://go.dev/play/p/KEKN93_iz-c

package main

import (
	"errors"
	"fmt"
)

var ErrNotFound = fmt.Errorf("not found")
var ErrUnauthorized = fmt.Errorf("unauthorized")

func main() {
	err := fmt.Errorf("error: %w: %w", ErrNotFound, ErrUnauthorized)
	fmt.Println(errors.Is(err, ErrNotFound))
	fmt.Println(errors.Is(err, ErrUnauthorized))
}

実行結果

true
true

というわけで、下記のように複数の関数を呼び出して、大元の呼び出し元でエラーハンドリングしたい場合に便利そうと思ったのでした。

Go Playground: https://go.dev/play/p/_zyokSjASA8

package main

import (
	"errors"
	"fmt"
)

var ErrNotFound = fmt.Errorf("not found")
var ErrUnauthorized = fmt.Errorf("unauthorized")

func main() {
	err := B()
	fmt.Println(errors.Is(err, ErrNotFound))
	fmt.Println(errors.Is(err, ErrUnauthorized))
}

func A() error {
	return fmt.Errorf("xxx: %w", ErrNotFound)
}

func B() error {
	if err := A(); err != nil {
		return fmt.Errorf("yyy: %w: %w", err, ErrUnauthorized)
	}
	return nil
}

Discussion