LoginSignup
41
17

More than 5 years have passed since last update.

xerrorsパッケージがWrapメソッドではなく : %w でラップする理由

Last updated at Posted at 2019-02-17

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.Newfmt.Errorf に渡したerrorをデフォルトで今回の仕様変更に対応させたかったようです。
つまりGo 1.13からは errors.Newfmt.Errorf で作成したエラーにもコールスタックの情報を付与したかったということです。これらの関数を実行すると、nowrapErrorwrapError のどちらかにラップされ、コールスタック情報を保持するようになります。

実際に比較してみたいと思います。

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に付与したかった。ベンチマークをとった結果としてはパフォーマンスの問題はなかった。

プロポーザル提案者のコメント

関連情報

41
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
17