go での error の返し方
go しばらく書いてると
someErr := errors.New("some error") func SomeFunc(arg string) error { ... return someErr } func main(){ if err := SomeFunc(a); err != nil{ if err == someErr { log.Println(err) } } }
のようなエラー処理はよくやる。 しかし、error に識別可能な情報があるのかどうか考えておく必要がある。
SomeFunc を数回呼ぶような場合、どの呼び出しでエラーが起きたのかは判断できない。
例えば、標準ライブラリの os.Open ではエラーには細かい情報が含まれる。
open /path/to: no such file or directory
関数を書くときにはその戻りの error に必要な情報を fmt.Errorf で埋めると良い。
しかし、動的な値を埋めると err == someErr
のようなエラー内容による分岐ができなくなる。(strings.Contains 等でできなくもないが筋悪)
標準ライブラリではこのような問題を解決するのにエラー型を用いている。
エラー型を用いて最初の例を書き直すと以下のようになる。
type someErr error someErr := errors.New("some error") func SomeFunc(arg string) error { ... return someErr(fmt.Errorf("some error: %s", reason)) } func main(){ if err := SomeFunc(a); err != nil{ if _, ok := err.(someErr); ok { log.Println(err) } } }
os.IsNotExist 等はこのタイプ判別した結果を bool として返している。
こうすることでエラーには適切な情報を含めつつ、エラー判別も行える。
運用フェーズを考えてしっかりエラー処理を書こう。