プログラムにはエラー処理はつきものです。 ファイルが開けなかったり、ネットワークに接続できなかったりする可能性があります。 予想可能なエラーは適切に処理するようにプログラムを組む必要があります。 コーヒーを淹れるプログラムでも、水が多すぎたり、豆が多すぎたり、お湯が少なすぎたりするかもしれません。
Goでは、エラーはerror
型で表されます。
エラーがあるかないかは、次のようにif
で比較することが多いでしょう。
err := f()
if err != nil {
// エラー処理
}
// これでもOK
if err := f(); err != nil {
// エラー処理
}
受け取ったエラーはログに吐いたり、情報を付加して呼び出し元にreturnしたりします。
panic
を起こしたり、無視することは極力さけるようにしましょう。
別のゴールーチンで行っている処理でエラーが発生する場合はどのようにハンドリングすればよいのでしょうか。 エラーも値なのでチャネルを使って伝搬する方法が考えられます。
しかし、単純な場合はチャネルでも問題ありませんが、sync.WaitGroup
などを使っているような複雑な場合については、チャンネルを用いると逆に煩雑になってしまう恐れがあります。
golang.org/x/sync/errgroup
という準標準なパッケージを使うことで、このようなパターンをうまくハンドリングすることができます。
errgroup
パッケージには、sync.WaitGroup
に似たerrgroup.Group
が提供されています。
sync.Wait
のAdd
メソッドやDone
メソッドの代わりに、Go
メソッドがあります。
Go
メソッドは引数で渡した関数をゴールーチンで実行してくれます。
この関数の戻り値はerror型でゴールーチンでエラーが発生した場合には適切に処理ができるようになっています。
Wait
メソッドを実行すると、Go
メソッドで呼び出された関数がすべて終了するまで処理がブロックされます。
もし、1つでもエラーを返す関数があれば、Wait
メソッドは戻り値で最初に発生したエラーを返します。
var eg errgroup.Group
eg.Go(func() error {
if err := f(); err != nil {
return err
}
})
eg.Go(func() error {
if err := g(); err != nil {
return err
}
})
if err := eg.Wait(); err != nil {
// エラー処理
}
boil
関数、grind
関数、brew
関数がエラーを返すようになっています。
sync.WaitGroup
の代わりにerrgroup.Group
を使うことでエラーハンドリングをできるようにしましょう。
errgroup
パッケージは外部パッケージであるため、go get
コマンドでインストールする必要があります。
$ go get -u golang.org/x/sync/errgroup
次のコマンドで実行することができます。
$ go run main.go
boil
関数に渡す水の量を2倍にしたりしてエラーが発生するようにしてみましょう。