目的
遅延評価、即時評価を理解する。
検証
main.go
package main
import (
"fmt"
"time"
)
//go:noinline
func Demo() func(int) {
aaa := 333
bbb := 444
closure := func(n int) {
fmt.Println("クロージャの中で見る aaa: ", aaa)
fmt.Println("クロージャの中で見る n: ", n)
}
defer func(n int) {
fmt.Println("deferの中で見る aaa: ", aaa)
fmt.Println("deferの中で見る bbb: ", n)
}(bbb)
aaa = 666
bbb = 888
closure(bbb)
go func() {
time.Sleep(time.Second * 3)
aaa = 1000
}()
return closure
}
//go:noinline
func main() {
myfunc := Demo()
myfunc(100)
time.Sleep(time.Second * 5)
myfunc(200)
}
~/praprago$ go run main.go
クロージャの中で見る aaa: 666
クロージャの中で見る n: 888
deferの中で見る aaa: 666
deferの中で見る bbb: 444
クロージャの中で見る aaa: 666
クロージャの中で見る n: 100
クロージャの中で見る aaa: 1000
クロージャの中で見る n: 200
注目すべきは、./main.go:10:2: moved to heap: aaa
の部分です。
クロージャが return されるので、それに備えて、aaa
をヒープにエスケープしてます。
~/praprago$ go build -gcflags "-m=1" main.go
# command-line-arguments
./main.go:13:13: can inline Demo.func1
./main.go:18:8: can inline Demo.func2
./main.go:18:2: can inline Demo.deferwrap1
./main.go:28:5: can inline Demo.func3
./main.go:26:9: inlining call to Demo.func1
./main.go:26:9: inlining call to fmt.Println
./main.go:26:9: inlining call to fmt.Println
./main.go:14:14: inlining call to fmt.Println
./main.go:15:14: inlining call to fmt.Println
./main.go:19:14: inlining call to fmt.Println
./main.go:20:14: inlining call to fmt.Println
./main.go:10:2: moved to heap: aaa
./main.go:13:13: func literal escapes to heap
./main.go:14:14: ... argument does not escape
./main.go:14:15: "クロージャの中で見る aaa: " escapes to heap
./main.go:14:55: aaa escapes to heap
./main.go:15:14: ... argument does not escape
./main.go:15:15: "クロージャの中で見る n: " escapes to heap
./main.go:15:53: n escapes to heap
./main.go:18:8: func literal does not escape
./main.go:19:14: ... argument does not escape
./main.go:19:15: "deferの中で見る aaa: " escapes to heap
./main.go:19:45: aaa escapes to heap
./main.go:20:14: ... argument does not escape
./main.go:20:15: "deferの中で見る bbb: " escapes to heap
./main.go:20:45: n escapes to heap
./main.go:26:9: ... argument does not escape
./main.go:26:9: "クロージャの中で見る aaa: " escapes to heap
./main.go:26:9: aaa escapes to heap
./main.go:26:9: ... argument does not escape
./main.go:26:9: "クロージャの中で見る n: " escapes to heap
./main.go:26:9: n escapes to heap
./main.go:28:5: func literal escapes to heap