Goのerrors.Isとerrors.Asの使いどころ

Go

errors.Is

エラーチェーンの中で、特定のエラーが存在するか確認する場合に使う。

以下の場合だと、queryDatabase関数内でErrDatabaseエラーが発生していて、それをmain関数内で存在しているか確認している。

もしqueryDatabase関数でエラーがない場合は、convertData関数内のErrConvertエラーの条件に該当する。

package main

import (
	"errors"
	"fmt"
)

type queryResult struct{}

// 独自エラーを定義
var (
	ErrDatabase = errors.New("database error")
	ErrConvert  = errors.New("convert error")
)

func queryDatabase() (result *queryResult, err error) {
	// なにかしらの処理をしたと仮定
	return result, fmt.Errorf("query failed: %w", ErrDatabase)
}

func fetchData() (result *queryResult, err error) {
	res, err := queryDatabase()
	if err != nil {
		// エラーをラップして返す
		return &queryResult{}, fmt.Errorf("fetchData failed: %w", err)
	}
	return res, nil
}

func convertData(res *queryResult) (result *queryResult, err error) {
	// resを変換したと仮定
	result = res
	return result, fmt.Errorf("convertData failed: %w", ErrConvert)
}

func process() (result *queryResult, err error) {
	res, err := fetchData()
	if err != nil {
		// エラーをラップして返す
		return &queryResult{}, fmt.Errorf("process failed: %w", err)
	}
	res, err = convertData(res)
	if err != nil {
		// エラーをラップして返す
		return &queryResult{}, fmt.Errorf("process failed: %w", err)
	}
	return res, nil
}

func main() {
	res, err := process()
	if err != nil {
		if errors.Is(err, ErrDatabase) {
			fmt.Println("エラーが発生しました: ErrDatabase")
		} else if errors.Is(err, ErrConvert) {
			fmt.Println("エラーが発生しました: ErrConvert")
		} else {
			fmt.Println("エラーが発生しました: ", err)
		}
	}

	fmt.Println(res)
}

errors.As

エラーチェーンの中に、特定の型のエラーが存在するか確認する場合に使う。

以下の場合だと、CustomError型のエラーがあり、process関数内で使用されている。

それをmain関数内で同じエラー型が存在するか確認している。

package main

import (
	"errors"
	"fmt"
)

// 独自エラー型を定義
type CustomError struct {
	Code    int
	Message string
}

func (e *CustomError) Error() string {
	return fmt.Sprintf("Code: %d, Message: %s", e.Code, e.Message)
}

func process() error {
	// カスタムエラーを返す
	return fmt.Errorf("operation failed: %w", &CustomError{Code: 404, Message: "not found"})
}

func main() {
	err := process()
	if err != nil {
		var myErr *CustomError
		if errors.As(err, &myErr) {
			fmt.Printf("CustomError: %v\n", myErr.Error())
		} else {
			fmt.Println("Other error:", err)
		}
	}
}