Golang中閉包與常用場景詳解
在很多的開源項目里,經(jīng)??吹介]包的運(yùn)用,在 Go語言中,函數(shù)類型是一種特殊的類型,函數(shù)類型可以像其他類型一樣被聲明、賦值給變量、作為參數(shù)傳遞。進(jìn)而有了匿名函數(shù)、閉包。本文將簡要記錄閉包的概念和一些常用的場景。
什么是閉包
Go函數(shù)可以是閉包。閉包是一個函數(shù)值,它從函數(shù)體外部引用變量。函數(shù)可以訪問被引用的變量并對其賦值;從這個意義上說,函數(shù)被“綁定”到變量上。-- a Tour of Go
一個最簡單的例子: 1~10的加法
package main import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos := adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), ) } } //OUTPUT //0 //1 //3 //6 //10 //15 //21 //28 //36 //45
上例中,adder函數(shù)返回一個閉包。在閉包內(nèi)部,它引用了外部的變量sum
。
閉包和匿名函數(shù)的區(qū)別
匿名函數(shù)是指在代碼中沒有明確命名的函數(shù),閉包是一個函數(shù)值,它可以訪問其詞法環(huán)境中捕獲的變量。匿名函數(shù)可以是閉包,也可以不是閉包。匿名函數(shù)引用了外部作用域中的變量,它就成為閉包。
func main() { x := 10 // 匿名函數(shù),不是閉包 anonymousFunc := func() { fmt.Println("匿名函數(shù):", x) } anonymousFunc() // 閉包 closureFunc := func() { fmt.Println("閉包:", x) } closureFunc() }
常見的應(yīng)用場景
閉包在實際編程中具有廣泛的應(yīng)用。以下是幾個常見的應(yīng)用場景:
- 保存狀態(tài): 通過捕獲外部變量,閉包可以在函數(shù)調(diào)用之間保留狀態(tài)信息,如迭代器
- 函數(shù)工廠: 根據(jù)不同的配置參數(shù)來動態(tài)創(chuàng)建函數(shù),
- 回調(diào)函數(shù):將一個函數(shù)作為參數(shù)傳遞給另一個函數(shù),通過閉包,捕獲一些上下文信息并執(zhí)行該函數(shù)
- 并發(fā)編程:可以安全地在多個goroutine中共享和修改變量,一種簡潔的方式
保存狀態(tài) -- 迭代器
package main import "fmt" func Iterator(values []int) func() (int, bool) { index := 0 return func() (int, bool) { if index >= len(values) { return 0, false } value := values[index] index++ return value, true } } func main() { numbers := []int{1, 2, 3, 4, 5} iterate := Iterator(numbers) for { value, ok := iterate() if !ok { break } fmt.Println(value) } } //OUTPUT: //1 //2 //3 //4 //5
上例中,index為閉包的共享狀態(tài)。Iterator創(chuàng)建一個閉包函數(shù),這個閉包函數(shù)用于迭代切片中的元素。其中,閉包每次執(zhí)行,index會遞增,直到循環(huán)結(jié)束。比如在很多開源框架的中間件中,會使用迭代器模式實現(xiàn)。
函數(shù)工廠
package main import "fmt" func FunctionFactory(operation string) func(int, int) int { switch operation { case "add": return func(a, b int) int { return a + b } case "subtract": return func(a, b int) int { return a - b } case "multiply": return func(a, b int) int { return a * b } case "divide": return func(a, b int) int { if b != 0 { return a / b } return 0 } default: return nil } } func main() { addFunc := FunctionFactory("add") subtractFunc := FunctionFactory("subtract") multiplyFunc := FunctionFactory("multiply") divideFunc := FunctionFactory("divide") fmt.Println(addFunc(5, 3)) fmt.Println(subtractFunc(10, 2)) fmt.Println(multiplyFunc(4, 5)) fmt.Println(divideFunc(10, 2)) fmt.Println(divideFunc(10, 0)) } //OUTPUT: 8 8 20 5 0
上例中,F(xiàn)unctionFactory分別提供加法、減法、乘法和除法的閉包函數(shù),并封裝為函數(shù)工廠,使得函數(shù)的創(chuàng)建更加靈活和可定制。
回調(diào)函數(shù)
package main import ( "fmt" "time" ) func PerformOperationAsync(input int, callback func(int)) { go func() { time.Sleep(2 * time.Second) result := input * 2 callback(result) }() } func main() { callback := func(result int) { fmt.Println("操作結(jié)果:", result) } PerformOperationAsync(5, callback) time.Sleep(3 * time.Second) } //OUTPUT //操作結(jié)果:10
上例中,使用匿名函數(shù)創(chuàng)建了一個閉包callback
,即回調(diào)函數(shù)。在執(zhí)行異步操作時,它會將計算結(jié)果result
傳遞給回調(diào)函數(shù)。比如,我們需要等待某個長時間的操作或者某個事件觸發(fā)之后的場景。
并發(fā)編程
package main import ( "fmt" "sync" "time" ) func ConcurrentTask(tasks []func() int) []int { results := make([]int, len(tasks)) wg := sync.WaitGroup{} for i, task := range tasks { wg.Add(1) go func(i int, task func() int) { defer wg.Done() results[i] = task() }(i, task) } wg.Wait() return results } func main() { tasks := []func() int{ func() int { time.Sleep(2 * time.Second) return 1 }, func() int { time.Sleep(1 * time.Second) return 2 }, func() int { time.Sleep(3 * time.Second) return 3 }, } results := ConcurrentTask(tasks) fmt.Println(results) // 輸出:[1 2 3] } //OUTPUT //[1 2 3]
上例中,for循環(huán)為每個任務(wù)創(chuàng)建一個匿名函數(shù)。這些匿名函數(shù)使用閉包來捕獲循環(huán)變量i
和任務(wù)函數(shù)task
。在每個匿名函數(shù)內(nèi)部,我們調(diào)用任務(wù)函數(shù),并將結(jié)果存儲在相應(yīng)的位置。
總結(jié)
本文主要學(xué)習(xí)記錄Go語言中一個強(qiáng)大、極具表現(xiàn)力的特性:閉包。包括閉包的基礎(chǔ)概念,和匿名函數(shù)的區(qū)別,以及一些常見的編程場景。閉包因為其靈活性,可塑性強(qiáng),在開源庫里廣泛運(yùn)用,對提升代碼的可維護(hù)性、拓展性上有比較大的幫助。
以上就是Golang中閉包與常用場景詳解的詳細(xì)內(nèi)容,更多關(guān)于Go閉包的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Ubuntu18.04 LTS搭建GO語言開發(fā)環(huán)境過程解析
這篇文章主要介紹了Ubuntu18.04 LTS搭建GO語言開發(fā)環(huán)境過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11