2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Go]ループ内でpanicが起こった時、ループを終了させずにrecoverする

Last updated at Posted at 2019-01-10

概要

Goでは、panicの乱用は推奨されないことが多いと思いますが、ループ処理中などに、不意にpanicを吐く外部パッケージが紛れ込んでしまった時など、panicを他のエラーと同様にハンドリングして処理を最後まで続けたいケースがありました。
今回は一つの解決の方針として、panicの発生する部分を無名関数でくるんで捕まえる、という方法を紹介します。

内容

例1:処理をそのままrecoverした場合


package main

import "fmt"

func main() {

	var j int
	var k int

	for i := 1; i < 10; i++ {
		// 回数
		fmt.Printf("i = %d\n", i)

		// panic時にはrecover
		defer func() {
			if err := recover(); err != nil {
				fmt.Println("recover:", err)
			}
		}()

		// panicを吐く可能性がある処理
		hoge(i, j)
		huga(i, k)
	}

}

func hoge(i int, j int) {
	return
}

func huga(i int, k int) {
	if i == 5 {
		panic("panic")
	}
	return

}

実行結果

i = 1
i = 2
i = 3
i = 4
i = 5
recover: panic

関数内でpanicが発生した時、deferを実行し、元の関数を終了する。
したがって、例1を実行すると i = 5 の時panicが発生し、deferでrecoverされるので正常終了するが、main関数が終了してしまうので、ループ処理も途中で終了してしまう。

例2:処理を無名関数でくるんでrecoverした場合

package main

import "fmt"

func main() {

	var j int
	var k int

	for i := 1; i < 10; i++ {
		// 無名関数でラップする
		func() {
			// 回数
			fmt.Printf("i = %d\n", i)

			// panic時にはrecover
			defer func() {
				if err := recover(); err != nil {
					fmt.Println("recover:", err)
				}
			}()

			// panicを吐く可能性がある処理
			hoge(i, j)
			huga(i, k)
		}()
	}

}

func hoge(i int, j int) {
	return
}

func huga(i int, k int) {
	if i == 5 {
		panic("panic")
	}
	return

}

実行結果

i = 1
i = 2
i = 3
i = 4
i = 5
recover: panic
i = 6
i = 7
i = 8
i = 9

例2は、ループの中身を無名関数で囲んだだけであるが、defer実施後に終了される関数が、無名関数となり、ループは無名関数の外側にあるので終了しない。(無名関数からローカル変数を参照できるので、処理に必要な引数の引き渡しも考慮する必要がない)

まとめ

Goでは、panicの多用は推奨されないことが多いのですが、そのため、逆に不意にpanicが混じった時にハンドリングできず困ることもあるかもしれません。今回は一つの解決法として、panicの発生する部分を無名関数でくるんで捕まえる、という方法を紹介しました。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?