はじめに
こんにちは! TIG の川口です。
本記事は Go 1.20リリース連載 の3本目です。Wrapping multiple errors についてお話します。
Release Note では、こちら の箇所になります。
Proposal は、こちら になります。
何が変わったか?
さて具体的に何が変わったかをはじめにおさえておきます。
Go 1.20 expands support for error wrapping to permit an error to wrap multiple other errors.
An error e can wrap more than one error by providing an Unwrap method that returns a []error.
The errors.Is and errors.As functions have been updated to inspect multiply wrapped errors.
The fmt.Errorf function now supports multiple occurrences of the %w format verb, which will cause it to return an error that wraps all of those error operands.
The new function errors.Join returns an error wrapping a list of errors.
要約すると、以下のようになるでしょうか。 (以降、wrapping multiple errors はマルチエラーと記載します)。
- エラーのラップが拡張されて、複数のエラーをラップしたマルチエラーを作成できるようになりました。
- error 型は、
[]error
を返すUnwrap
メソッドを提供することで、マルチエラーとできます。 - マルチエラーに関して、
errors.Is
関数とerrors.As
関数により、検査できるようになりました。 fmt.Errorf
関数とerrors.Join
関数により、マルチエラーを作成できるようになりました。- (マルチエラーを []error に復元する方法については言及していません)。
目次
それでは以降、下記の順に則ってお話していこうと思います。
- マルチエラーの作成方法
- マルチエラーの検査方法
- マルチエラーを []error に復元する方法
- どんなときに使えるか?
また、本稿では以下の version を利用しています。
$ go version |
マルチエラーの作成方法
マルチエラーの作成方法に関しては、先述の通り以下の2パターンあるようです。
package main |
ただしそれぞれ作成される error の型は異なります。詳細は、以下を参照ください。
またこちらの実装を見ると、どちらも、[]error
を返す Unwrap
メソッドが提供されていることがわかるかと思います。
マルチエラーの検査方法
今までは、 errors.Is
, errors.As
を使ってラップされたエラーの検査を行うことができました。
今後はこれらの関数が、マルチエラーにも対応するようです。
package main |
基本的な考え方は、既存のものと変更はなさそうです。
既存のラップされたエラーの機構と互換性を保つように Unwrap() error
と Unwrap() []error
メソッドのどちらでも再帰的に処理できるようになっていそうですね。
マルチエラーを []error に復元する方法
こちらに関しては言及がなかったので、特別何か専用の関数が増えたりということは今のところなさそうですね。
こちらを実現しようとすると、👆の errors.Is
, errors.As
等の実装を見ていただいた方はわかるかと思いますが、以下のようにしなければならなさそうです。
package main |
ちなみに、そのまま errors.Unwrap
を利用した際には、以下のように nil が返ってきてしまいます。
package main |
こちらはややおかしな挙動ではありますが、errors.Unwrap
の実装を見ると理解できます。
マルチエラーは、Unwrap() []error
メソッドは持っていても、Unwrap() error
メソッドを持っていないからですね。
利用する場面
利用する場面としては、パッと思いつくものとしては「ベストエフォート的な複数処理」などがあるでしょうか。
例えば、「ベストエフォート的に各ユーザーに対して一人ずつメールを送信していく」などの場面では使えそうです。
コードとしては以下のようなイメージです(一括で処理できるように模索するべきとか。並列に処理をした方が良いとか。色々あるかもですが、その辺のお話はいったんおいておきます!!!)
func run() { |
このとき、run()
の返り値に error を増やしたいとなったときになかなかどのようなコードを書くか悩ましくなることが想像できると思います。
今までであれば、以下のようなサードパーティ製のものを使ったり自作のエラーパッケージを作成したりして実現していた方もいると思います。
それが今後は以下のようにして書き直せるようになるのかなと。
func run() error { |
おわりに
新しく拡張された Wrapping multiple erros についての記事でした!
用途がたくさんあるというわけではない気もしますが、今後の error handling の手法の1つとしておさえておいたほうが良いものになるかもしれません? 🤔
次は宮永さんの timeのアップデート です。