Skip to content

Latest commit

 

History

History

step05

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

STEP 5: ゴールーチンとエラー処理

エラー処理

プログラムにはエラー処理はつきものです。 ファイルが開けなかったり、ネットワークに接続できなかったりする可能性があります。 予想可能なエラーは適切に処理するようにプログラムを組む必要があります。 コーヒーを淹れるプログラムでも、水が多すぎたり、豆が多すぎたり、お湯が少なすぎたりするかもしれません。

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.WaitAddメソッドや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倍にしたりしてエラーが発生するようにしてみましょう。