errors.Join が返す error は interface { Unwrap() []error } を満たす
Go Duck Typing
いまのプロジェクトでは aereal/otelgqlgen をつかっており、OTel トレースにエラー情報を付与する際に WithErrorSelector の機構をつかって span.SetStatus(codes.Error, errs.Error()) のように記録したくない場合の関数をはさむことができる
理由としては OTel トレース情報は Exporter に渡されて Datadog などに渡されるわけだが、モニタリングなどであるWindowで GraphQL エラー数などをカウントしているケースにおいて、実はノイズとなるエラーなのでエラーとして記録したくないというケースは多い
で、go-multierror や標準ライブラリのエラーの混在があるなか、選り分けをするケースにおいて Type Assertion を使って、これがわりと Go らしいのではないかと思った話
ざくっとコードは以下のような感じだ
code:errors.go
func unwrap(err error) []error {
// https://pkg.go.dev/github.com/hashicorp/go-multierror#Error.WrappedErrors
if u, ok := err.(interface { WrappedErrors() []error }); ok {
return u.WrappedErrors()
}
// https://pkg.go.dev/errors#Join
// > A non-nil error returned by Join implements the Unwrap() []error method.
if u, ok := err.(interface { Unwrap() []error }); ok {
return u.Unwrap()
}
return nil
}
シグニチャに合致するかどうかを Comma Ok Idiom をつかって表現する
ガーと鳴けばアヒルであるといった喩えがそのままコードになったような表現だなと思った(日記
ちなみに標準ライブラリの errors.As, errors.Is も同じような選別の仕方で Unwrap するようになっている
https://github.com/golang/go/blob/8320fe8f0e5283eb67429de30b4e24be6a85c7a7/src/errors/wrap.go#L53-L78