Like Share Discussion Bookmark Smile

J.J. Huang   2025-03-04   Getting Started Golang 04.函式   瀏覽次數:次   DMCA.com Protection Status

Go | 匿名函式與閉包的應用

💬 簡介

在 Go 語言中,函式不僅是程式的基本單元,也可以作為變數傳遞,甚至動態生成新的函式。其中,「匿名函式」「閉包」是兩個重要的進階概念,它們能讓程式碼更加靈活,也能解決一些傳統函式難以處理的需求。

在本篇文章中,我們將探討:

  • 什麼是匿名函式?
  • 什麼是閉包?
  • 這些概念的應用場景
  • 具體範例,讓你更容易理解

圖片來源:Gophers


🔎 什麼是匿名函式?

匿名函式(Anonymous Function) 是指沒有名稱的函式,這類函式通常用於臨時性的邏輯,並且可以直接賦值給變數或當作參數傳遞。

1️⃣ 基本匿名函式

  • 範例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package main

    import "fmt"

    func main() {
    // 定義匿名函式並立即執行
    func() {
    fmt.Println("這是一個匿名函式")
    }()
    }

    📝 在這段程式碼中,匿名函式定義後立即執行。這種方式適用於只需要使用一次的函式,例如初始化設定。

2️⃣ 將匿名函式賦值給變數

  • 範例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package main

    import "fmt"

    func main() {
    add := func(a, b int) int {
    return a + b
    }
    fmt.Println("3 + 5 =", add(3, 5))
    }

    📝 在這裡,add 變數儲存了一個匿名函式,並可以像一般函式一樣使用。


🔎 什麼是閉包?

閉包(Closure) 是指一個函式「捕捉並保存」外部變數,即使該變數已經超出作用域,仍然能夠被函式存取。

1️⃣ 簡單閉包

  • 範例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    package main

    import "fmt"

    func counter() func() int {
    count := 0
    return func() int {
    count++
    return count
    }
    }

    func main() {
    next := counter()
    fmt.Println(next()) // 1
    fmt.Println(next()) // 2
    fmt.Println(next()) // 3
    }

    📝 這段程式碼的 counter 函式返回了一個匿名函式,而這個匿名函式「記住」了 count 變數,即使 counter 函式已經執行完畢,count 仍然存在於記憶體中。
    這就是閉包的特性:它能夠維持外部變數的狀態。


🚀 應用場景

1️⃣ 用於回呼函式(Callback)

匿名函式經常被用作回呼函式,這在事件處理或非同步操作中很常見。

  • 範例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package main

    import "fmt"

    func process(data int, callback func(int)) {
    result := data * 2
    callback(result)
    }

    func main() {
    process(10, func(result int) {
    fmt.Println("處理結果:", result)
    })
    }

    📝 在這個例子中,process 函式接受一個回呼函式 callback,讓我們可以自訂資料處理後的行為。

2️⃣ 責任鏈模式(Chain of Responsibility)

閉包可以用來實現「責任鏈模式」,讓多個函式組合在一起,依序處理請求。

  • 範例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package main

    import "fmt"

    type Handler func(int) int

    func main() {
    multiply := func(next Handler) Handler {
    return func(n int) int {
    return next(n * 2)
    }
    }

    add := func(next Handler) Handler {
    return func(n int) int {
    return next(n + 3)
    }
    }

    process := multiply(add(func(n int) int { return n }))
    fmt.Println("最終結果:", process(5)) // (5 + 3) * 2 = 16
    }

    📝 這種模式常見於中介層(Middleware)處理,例如 HTTP 請求的前置處理。

3️⃣ 動態函式生成

閉包可以根據不同的條件動態產生函式,使程式更具彈性。

  • 範例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package main

    import "fmt"

    func multiplier(factor int) func(int) int {
    return func(n int) int {
    return n * factor
    }
    }

    func main() {
    double := multiplier(2)
    triple := multiplier(3)
    fmt.Println("5 的兩倍:", double(5)) // 10
    fmt.Println("5 的三倍:", triple(5)) // 15
    }

    📝 這種方式可以用於建構不同的數學運算、條件處理等應用。


⚠️ 注意事項

  • 避免記憶體洩漏:閉包可能會導致變數長期存在於記憶體中,應避免在無限迴圈或長時間執行的程式中持續產生新的閉包。
  • 變數共享問題:如果多個閉包共享相同的變數,可能會導致意外的結果。
  • 確保閉包的正確性:使用閉包時,應確保變數的作用域與生命周期符合預期。

🎯 總結

  • 匿名函式 允許我們定義即時執行的函式,或將函式存入變數。
  • 閉包 讓函式能夠記住並存取外部變數,即使外部函式已經返回。
  • 它們廣泛應用於 回呼函式、責任鏈模式、動態函式生成 等場景。
  • 在使用閉包時,應注意記憶體管理與變數作用域,以避免潛在問題。

透過理解這些概念,你可以寫出更加靈活、可維護的 Go 程式!🚀

最後建議回顧一下 Go | 菜鳥教學 目錄,了解其章節內容。


註:以上參考了
Go