hakeの日記

Windows環境でプログラミングの勉強をしています。

Go言語 - 無名関数とクロージャ

ある関数foo内で定義された無名関数は、foo内のローカル変数にアクセスできる。

package main
import "fmt"

func foo() {
	var s string = "hello foo"
	
	f := func(){
		fmt.Println(s)
	}
	f()
}

func main() {
	foo() //-> hello foo
}


関数fooの戻り値として返された無名関数も同様にローカル変数にアクセスできる。

package main
import "fmt"

func foo() func(){
	var s string = "hello foo"
	
	f := func(){
		fmt.Println(s)
	}
	return f
}

func main() {
	a := foo()
	a()         //-> hello foo


そして、その関数foo内のローカル変数の値は無名関数毎に保存される。
こういうのをクロージャというらしい、以前から単語だけは目にしていましたが初めて理解できた気がします。

  • その関数が定義された環境への参照を持った関数をクロージャというみたい。
package main
import "fmt"

func foo(m string) func(string){
	var s string = m
	
	f := func(n string){
		fmt.Println(s + n)
	}
	return f
}

func main() {
	hello := foo("hello ")
	bye   := foo("bye ")
	hello("Taro")          //-> hello Taro
	bye("Hanako")          //-> bye Hanako
	hello("Jiro")          //-> hello Jiro
}


無名関数から、元の関数のローカル変数を変更することもできます。
以下はそのサンプルです。関数makeFibはフィボナッチ数列を発生する無名関数を返す関数で、無名関数が実行される毎に更新されるFib(n)とFib(n-1)の値をローカル変数に保持しています。

package main
import "fmt"

func makeFib() (func()int) {
	var c1 int = 0
	var c2 int = 1
	f := func()int{
		var c int = c2
		c2 = c1 + c
		c1 = c
		return c
	}
	return f
}

func main() {
	genFib := makeFib()
	for i:=0; i<10; i++ {
		fmt.Println(genFib())
	}
}