Go 言語の無名関数とクロージャ
Go の関数の基礎については「Go 言語の関数」をご覧ください。
Go 言語の無名関数
Go の関数はひとつの型として認識されて、関数本体はその値となります。
関数の型のことを特に「シグネチャ」(signature) ともいいます。
無名関数を作るには func キーワードに続けてすぐに引数リストを書きます。
次の例では無名関数を作り、それを hello という名前の変数に代入してから呼び出しています。
package main
import "fmt"
func main() {
// hello という変数に無名関数を代入
hello := func(name string) {
fmt.Println("Hello", name, "!")
}
// hello の型を表示
fmt.Printf("%T\n", hello) // func(string)
// hello の呼び出し
hello("John") // Hello John !
}
関数を変数に代入しないで、いきなり呼ぶ場合は次のようにします。
func(name string) {
fmt.Println("Hello", name, "!")
}("John")
これは「即時実行関数」 (IIFE) などとも呼ばれます。
Go 言語のクロージャ
Go では無名関数を利用して、クロージャ (closure) を作成することができます。
クロージャは、関数の中で作成される関数として実装されて、関数作成時点の変数を閉じ込めることができます。
具体例を見るとわかりやすいので、クロージャの具体例を見てみましょう。
次の例で、count という変数には 「int を返す関数」がセットされます。
package main
import "fmt"
func main() {
count := func() func() int {
c := 0
return func() int {
c++
return c
}
}()
count()
count()
fmt.Printf("%d\n", count()) // 3
}
しかし、単純に func() int というシグネチャを持つ関数をセットしているのではなく、 無名関数の戻り値として func() int というシグネチャの関数がセットされているところがポイントです。
外側の関数 (A) の戻り値が func() int というシグネチャの関数 (B)。B は A を呼び出した結果として、呼び出し元に返されます。
B では A 内で宣言された変数 c を使っています。A は一度実行して B を返してしまったら、 再度呼び出す方法はありません。 しかし A 内で宣言された変数 c は、 B の中で使い続けることができるのです。
言い方を換えれば、この形になると変数 c は、直接アクセスすることはできず、戻り値として返された関数内からしかアクセスできなくなります。
このように、関数の中で作成された関数が、親関数の変数を閉じ込めた形になる関数をクロージャといいます。
クロージャは、ここで使われた変数 c のように、変数を保護したりするためなどによく利用されます。
以上、ここでは Go の無名関数やクロージャについて説明してみました。