Go 的函式是一等公民,閉包捕捉的是變數本身
函式在 Go 裡可以當值傳遞、當參數、當回傳值,也可以就地寫成匿名函式——跟 JS 一樣。
// 當變數
add := func(x, y int) int { return x + y }
fmt.Println(add(1, 2))
// 當參數
func apply(nums []int, f func(int) int) []int { ... }
// 當回傳值:這就是閉包
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
c := counter()
c() // 1
c() // 2
c() // 3count 在 counter() 回傳之後沒有消失,因為內層函式還引用著它。閉包捕捉的是變數本身,不是當下的值——所以每次呼叫 c() 動到的都是同一個 count。
而每次呼叫 counter() 會產生各自獨立的 count:
c1 := counter()
c2 := counter()
c1(); c1() // c1 → 2
c2() // c2 → 1,互不干擾跟 JS 的差別在於:Go 有 GC 但沒有 var 提升那類問題,而且從 Go 1.22 起迴圈變數每次疊代各自一份之後,for 迴圈裡起 goroutine 捕捉迴圈變數的經典陷阱也消失了。