クロージャーの基本・利用例【夏休みにGo vol.12】

こんにちは、しーたです。
今日は「クロージャー」というものについて学んでいきます。少しややこしいです。

クロージャーの基本

呼び出す関数内の変数を、ローカル変数のように(?)扱うことができます。
実際にクロージャーを用いたインクリメントの例を見てみましょう。

func incrementGenerator() func() int {
	x := 0
	return func() int {
		x++
		return x
	}
}

func main() {
	counter := incrementGenerator()
	fmt.Println(counter())
	fmt.Println(counter())
	fmt.Println(counter())
	fmt.Println(counter())
}

画像1

このように、xが初期化されずに正しくインクリメントされていていることが分かります。

一方、クロージャーを用いずに似たようなプログラムを書くとこのようになります。

func incrementGenerator() int {
	x := 0
	x++
	return x
}

func main() {
	fmt.Println(incrementGenerator())
	fmt.Println(incrementGenerator())
	fmt.Println(incrementGenerator())
	fmt.Println(incrementGenerator())
}

画像3

当然ですがxの値が毎回初期化され、出力は毎回0になっています。


クロージャーの利用例

例えば、半径rの円の円周Lを求めるプログラムを書くとします。
円周率が3.14の場合、3.141592の場合それぞれについて計算します。

func circumference(pi float64) func(r float64) float64 {
	return func(r float64) float64 {
		return 2 * r * pi
	}
}

func main() {
	c1 := circumference(3.14) //pi=3.14の場合
	fmt.Println(c1(2))        //r=2の場合
	fmt.Println(c1(5))        //r=5の場合

	c2 := circumference(3.141592) //pi=3.141592の場合
	fmt.Println(c2(2))            //r=2の場合
	fmt.Println(c2(5))            //r=5の場合
}

画像3

このように、クロージャーは1つの引数はあまり変化せず、もう1つが頻繁に変化する場合に効果を発揮します。

同じプログラムをクロージャーなしに書こうとすれば、以下のように同じ引数を何度も書く必要があります。これは保守性(プログラムの修正しやすさ)に影響します。

func circumference(pi float64, r float64) float64 {
	return 2 * r * pi
}

func main() {
	fmt.Println(circumference(3.14, 2))
	fmt.Println(circumference(3.14, 5))
	fmt.Println(circumference(3.141592, 2))
	fmt.Println(circumference(3.141592, 5))
}


以上です。それでは!

いいなと思ったら応援しよう!