クロージャ【Go】
クロージャとは、関数と関数内で参照する変数をまとめた機能のことです。
引数で指定されない変数を、内部に保持する事ができます。
Goでは、返り値に無名関数を使用して実現します。
func incrementGenerator() func() int { x := 0 // 内部で使用する変数を、代入時に1度だけ初期化 return func() int { x++ return x } } func main() { counter := incrementGenerator() // x := 0と無名関数の代入が行われる fmt.Println(counter()) // 1 無名関数の内部の処理だけが行われる fmt.Println(counter()) // 2 同上 }
また、クロージャの返り値を複数にして、以下のようにリセット用関数を返すこともできます。
func incrementGenerator() (func() int, func()) { x := 0 // 内部で使用する変数を代入時に1度だけ初期化 gen := func() int { x++ return x } reset := func() { x = 0 } return gen, reset } func main() { counter1, reset1 := incrementGenerator() // x := 0と無名関数の代入が行われる counter2, _ := incrementGenerator() // x := 0と無名関数の代入が行われる。resetは使用しないため破棄 fmt.Println(counter1()) // 1 fmt.Println(counter1()) // 2 fmt.Println(counter2()) // 1 reset1() fmt.Println(counter2()) // 2 counter2のxはreset1()の影響を受けない fmt.Println(counter1()) // 1 }
クロージャの変数は、他クロージャの変更による影響を受けません。
クロージャは、異なる条件を保存して計算するときに便利です。
例えば消費税率を保存して計算するために、次のようできます。
(切り捨てなどは考慮していません)
func bill(tax float64) func(total float64) float64 { return func(total float64) float64 { return total * (1 + tax) } } func main() { price8 := bill(0.08) fmt.Println(price8(100)) // 108 fmt.Println(price8(200)) // 216 price5 := bill(0.05) fmt.Println(price5(100)) // 105 fmt.Println(price5(200)) // 210 }
次のようにクロージャの引数に関数を用いると、
さらに複雑なパターン分けに対応する事ができます。
func sliceCalc(f func(x int) int) func([]int) []int { return func(ary []int) []int { // 短縮のため、ここで変数名aryを記述 buff := make([]int, len(ary)) // 結果を格納するスライスの作成 for i, v := range ary { // for rangeは配列やスライスのloopを簡単にできる。indexとvalueを返す buff[i] = f(v) // スライスの各要素を引数の関数で計算し、結果格納用スライスに格納 } return buff } } func square(x int) int{ return x * x } func x2(x int) int { return x * 2 } func main() { a := []int {1, 2, 3, 4, 5} squareSlice := sliceCalc(square) x2Slice := sliceCalc(x2) fmt.Println(squareSlice(a)) // [1 4 9 16 25] fmt.Println(x2Slice(a)) // [2 4 6 8 10] fmt.Println(sliceCalc(square)(a)) // この様にも書ける fmt.Println(sliceCalc(x2)(a)) // この様にも書ける }
好ましいかどうかは状況次第ですが、引数とする関数内で分岐すれば、パターン分けは広がります。
参考
www.geocities.jp