Go | 匿名函式與閉包的應用
💬 簡介
在 Go 語言中,函式不僅是程式的基本單元,也可以作為變數傳遞,甚至動態生成新的函式。其中,「匿名函式」與「閉包」是兩個重要的進階概念,它們能讓程式碼更加靈活,也能解決一些傳統函式難以處理的需求。
在本篇文章中,我們將探討:
- 什麼是匿名函式?
- 什麼是閉包?
- 這些概念的應用場景
- 具體範例,讓你更容易理解
圖片來源:Gophers
🔎 什麼是匿名函式?
匿名函式(Anonymous Function) 是指沒有名稱的函式,這類函式通常用於臨時性的邏輯,並且可以直接賦值給變數或當作參數傳遞。
1️⃣ 基本匿名函式
- 範例:
1
2
3
4
5
6
7
8
9
10package main
import "fmt"
func main() {
// 定義匿名函式並立即執行
func() {
fmt.Println("這是一個匿名函式")
}()
}📝 在這段程式碼中,匿名函式定義後立即執行。這種方式適用於只需要使用一次的函式,例如初始化設定。
2️⃣ 將匿名函式賦值給變數
- 範例:
1
2
3
4
5
6
7
8
9
10package 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
18package 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
14package 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
22package 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
16package 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