defer、panicとrecover

編集

Goでは、ゼロ除算などのランタイムエラーが発生すると、組み込み関数 panic が呼び出されます(詳細は ランタイム・パニック を参照してください)。

標準の動作では、panic が発生するとプログラムは終了しますが、defer で登録された関数(またはメソッド)は panic が発生した際にも呼び出されます。defer の中で組み込み関数 recover を呼び出すことで、panic の引数を取得することができます。

deferpanicrecover を用いた例外処理は強力ですが、構造化されていないため、パッケージの API として使用するには適していません。したがって、パッケージを超えたエラー処理には適用を避けるべきです。

パッケージを超えたエラー処理には、error インターフェースの利用が適しています。

コード例
package main

import "fmt"

func main() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("%v -- recovered(main)\n", err)
		}
	}()

	fmt.Println(subr())
	panic("User raised panic")
	fmt.Println("fin")
}

func subr() (i int) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("%v -- recovered(subr)\n", err)
			i = 0
		}
	}()
	a, b := 1, 0
	a = a / b
	fmt.Printf("a = %d, b = %d\n", a, b)
	return a
}
実行結果
./prog.go:13:2: unreachable code
Go vet exited.

runtime error: integer divide by zero -- recovered(subr)
0
User raised panic -- recovered(main)

Program exited.