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()   // 3

countcounter() 回傳之後沒有消失,因為內層函式還引用著它。閉包捕捉的是變數本身,不是當下的值——所以每次呼叫 c() 動到的都是同一個 count

每次呼叫 counter() 會產生各自獨立的 count

c1 := counter()
c2 := counter()
c1(); c1()   // c1 → 2
c2()         // c2 → 1,互不干擾

跟 JS 的差別在於:Go 有 GC 但沒有 var 提升那類問題,而且從 Go 1.22 起迴圈變數每次疊代各自一份之後,for 迴圈裡起 goroutine 捕捉迴圈變數的經典陷阱也消失了。

相關:Go 函式的多回傳值與具名回傳值Goroutine 是用 go 關鍵字啟動的輕量任務