https://qiita.com/yoshinori_hisakawa/items/15bf0307245744deb4fc
以下のような問題がある。この問題への回答が言語の機能としてサポートされていない。
errorから呼び出し階層を得られる保証がない
errorは単なる戻り値であるため、main関数→関数A→関数Bという呼び出しをしているとき、関数Bでerrorが発生した場合、以下のようなコードだとスタックトレースが分からない。
func main() { result, err = A() if err != nil { //どういう呼び出しで発生したerrなのか分からない! } } func A() (string, error) { result, err = B(); if err != nil { return "", err } return string, nil } func B() (string, error) { if is成功 { return "result", nil } else { return "", error.New("func B err!") } }
それをうまく扱うためにerrorsというパッケージがあり、呼び出し階層ごとのエラーのラッピングと、そこから本来のエラーを取り出す仕組みが提供されている。
func main() { result, err = A() if err != nil { fmt.Println("err info:", err) // これでスタックトレースが表示される originalErr = errors.Cause(err) // 本来のエラーを取り出す } } func A() (string, error) { result, err = B(); if err != nil { return "", errors.Wrap(err, "func A err!") // ラッピング } return string, nil } func B() (string, error) { if is成功 { return "result", nil } else { return "", errors.New("func B err!") } }
errorとしてどのような値を戻すべきか
複数種類のエラーが戻る可能性がある場合、どの種類のエラーが戻されたかを判定する方法がいくつかある。
下にいくほど、コードとしては正しいがめんどくさい。
1.「エラー値 errors.New()で作成される値」を戻す。
2.「エラー型 errorインターフェースを実装した型」を戻す。型の違いで判定する。
3.「エラー型が実装したインターフェース」の違いで判定する。エラーはerrorインターフェースと、エラー種類インターフェースを実装した型として定義。