[Golang] エラーの型を判別する – error, type

Goでエラー返す関数の戻り値の型は大抵ただのerror型ということが多いです。

そのままだと、errorの種類によって処理を変えたくても、error.Error()で取得できるエラー文字列しか情報がありません。

今回はそんなerrorの型を判別する処理について書いていきます。

今回のコードはこちらにもアップしてあります。

https://github.com/pei223/go_samples/blob/master/error_sample/error_sample.go

独自のエラー型を実装


Goのerrorインターフェースは以下のように文字列を返すError()関数の実装のみです。

type error interface {
  Error() string
}

なので、独自のエラー型は以下のように実装すればいいです。

今回はエラーコード付きのerror、エラーの詳細情報を持つerrorを定義します。

package error_sample

import (
	"fmt"
)

// エラーコードの型
type ErrorCode = uint16

// エラー詳細情報
type ErrorDetail struct {
	Code    ErrorCode
	Message string
}

// エラーコード付きのerror
type ErrorWithErrorCode struct {
	Code    ErrorCode
	Message string
}

// エラー詳細情報を持つerror
type ErrorWithDetail struct {
	Message string
	Details []ErrorDetail
}

// errorインターフェース実装
func (err *ErrorWithErrorCode) Error() string {
	return err.Message
}

// エラーコード返却関数
func (err *ErrorWithErrorCode) ErrorCode() ErrorCode {
	return err.Code
}

// errorインターフェース実装
func (err *ErrorWithDetail) Error() string {
	return err.Message
}

// エラー詳細情報返却関数
func (err *ErrorWithDetail) ErrorDetails() []ErrorDetail {
	return err.Details
}

エラー型の判別処理


上記のエラーを判別する処理は型switchで実装できます。

switch err.(type)でerrorの型を判別できます。


func IdentifyAndOutputError(err error) {
  // エラー型判別
	switch err := err.(type) {
  // エラーコードを持つerrorの場合
	case *ErrorWithErrorCode:
		fmt.Printf("[ErrorWithErrorCode]\nCode: %d, Message: %s\n", err.Code, err.Message)
  // エラー詳細情報を持つerrorの場合
	case *ErrorWithDetail:
		fmt.Printf("[ErrorWithDetail]\nMessage: %s, \n", err.Message)
		for i, detail := range err.Details {
			fmt.Printf("\t%d: Code: %d, Message: %s\n", i, detail.Code, detail.Message)
		}
	}
}

以下のコードのDoErrorSamples()を実行するとエラー型が判別できていることが分かります。

func DoErrorSamples() {
	fmt.Println("\n\nエラー型識別テスト")
	err1 := GenError(1)
	IdentifyAndOutputError(err1)
	fmt.Println()
	err2 := GenError(2)
	IdentifyAndOutputError(err2)
}

func GenError(num uint16) error {
	if num%2 == 0 {
		return &ErrorWithErrorCode{
			Code:    num,
			Message: fmt.Sprintf("Error%d", num),
		}
	}
	return &ErrorWithDetail{
		Message: fmt.Sprintf("Error%d", num),
		Details: []ErrorDetail{
			{
				Message: "Detail1",
				Code:    1,
			},
			{
				Message: "Detail2",
				Code:    2,
			},
		},
	}
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です