😺
Go言語におけるエラーハンドリングベストプラクティス
もう散々書かれている話だけど、Go に触るたびに毎回調べ直す羽目になっているので、忘備録としてまとめておく
結論
-
errors
パッケージは使わない - その代わりに
golang.org/x/xerrors
パッケージを使う - エラーを自分で作成するときは
xerrors.New
もしくはxerrors.Errorf
を使う - 関数から受け取ったエラーを返すときは
xerrors.Errorf(": %w", err)
を使う- コメントを付与したいときは
xerrors.Errorf("comment: %w", err)
- コメントを付与したいときは
- エラーの出力は
fmt.Printf("%+v\n", xerrors.Errorf(": %w", err))
こんな感じ
具体例
package main
import (
"fmt"
"os"
"strconv"
"golang.org/x/xerrors"
)
func main() {
if err := f(os.Args[1]); err != nil {
fmt.Printf("%+v\n", xerrors.Errorf(": %w", err))
}
}
func f(s string) error {
n, err := strconv.Atoi(s)
if err != nil {
return xerrors.Errorf(": %w", err)
}
if n < 10 {
return xerrors.Errorf("n is %d", n)
}
return nil
}
説明
- 標準の
errors
パッケージを使うとスタックトレースが取れず、どこでエラーが発生したのか全くわからないので、何らかの手段を用意する必要があり、その一番妥当な選択肢がgolang.org/x/xerrors
。 - API は
github.com/pkg/errors
の方が好みだけどすでにアーカイブされており、今後メンテナンスされない見込みなので使わない。-
xerrors
も全然コミットされていないけど、This package is based on the Go 2 proposal
と書いてあり、Go 言語のメインストリームの実装と言えそうだし特にバグも無さそうなので、良い意味で安定しているのかも。
-
-
xerrors.Errorf
は実行した関数のスタックトレースをとっているわけではなく、あくまでErrorf
を実行した位置をスタックトレースに追加していくだけっぽいのでちょっと使いづらい。出力時にもスタックトレースを付与した方がいい。 -
xerrors.Errorf("%w", err)
と:
を書かずにラップすると、受け取ったエラーのコメントを勝手にコメントとして付与してしまい、とてもみづらいことになる。
Discussion
知見の共有ありがとうございます。
コメントいただきありがとうございます!
恥ずかしながら
pkg/errors
がアーカイブされている事実に気づいておりませんでした。大幅に記事を書き直しました。
僕としては、
fmt.Errorf
ではスタックトレースが付与されないようでしたのでやはりxerrors
を使う方針にしました!まだ勘違いがあるかもしれないので、またコメントいただけたら嬉しいです。
メンテナンス具合はxerrorsもトントンのようですが、スタックトレースがMustであればどちらかを選択して使うんですかねぇ…🤔
スタックトレースってどこまで必要なんだろう?と私自身考えるきっかけになりました、ありがとうございました…!