Goの新しいerrors パッケージ xerrors(Go 1.13からは標準のerrorsパッケージに入る予定) で紹介した通り、Goの新しいerrors パッケージではpkg/errors パッケージとは異なりWrap
メソッドではなく : %w
でラップする仕様となっています。
// pkg/errors
errors.Wrap(err, "message")
// xerrors
xerrors.Errorf("message: %w", err)
多くの方が違和感を持つと同時に Wrap
メソッドではいけないのか?と疑問を持ったと思います。
この記事ではその理由をProposal: Go 2 Error Inspectionから考察します。
: %w
の理由
- We included a Frame in the errors returned by errors.New and fmt.Errorf so that existing Go programs could reap the benefits of location information. We benchmarked the slowdown from fetching stack information and felt that it was tolerable.
- We changed the behavior of fmt.Errorf for the same reason: so existing Go programs could enjoy the new formatting behavior without modification. We decided against wrapping errors passed to fmt.Errorf by default, since doing so would effectively change the exposed surface of a package by revealing the types of the wrapped errors. Instead, we require that programmers opt in to wrapping by using the new formatting verb %w.
上記の文章からerrors.New
や fmt.Errorf
に渡したerrorをデフォルトで今回の仕様変更に対応させたかったようです。
つまりGo 1.13からは errors.New
や fmt.Errorf
で作成したエラーにもコールスタックの情報を付与したかったということです。これらの関数を実行すると、nowrapError
と wrapError
のどちらかにラップされ、コールスタック情報を保持するようになります。
実際に比較してみたいと思います。
err := fmt.Errorf("base error")
fmt.Printf("%+v", err)
もしフォーマットでラップする仕様にしなかった場合の出力結果
base error
フォーマットでラップする仕様にした場合の出力結果(Go 1.13以降)
base error:
main.main
/Users/sonatard/tmp/xerrors/main.go:13
まとめ
xerrorsパッケージがWrapメソッドではなく : %w
でラップする理由は、インターフェースの下位互換は保ちつつ、コールスタックの情報をerrorに付与したかった。ベンチマークをとった結果としてはパフォーマンスの問題はなかった。
プロポーザル提案者のコメント
- https://github.com/golang/go/issues/29934#issuecomment-464201672
- https://github.com/golang/go/issues/29934#issuecomment-464208038