Golang中閉包與常用場(chǎng)景詳解
在很多的開源項(xiàng)目里,經(jīng)??吹介]包的運(yùn)用,在 Go語(yǔ)言中,函數(shù)類型是一種特殊的類型,函數(shù)類型可以像其他類型一樣被聲明、賦值給變量、作為參數(shù)傳遞。進(jìn)而有了匿名函數(shù)、閉包。本文將簡(jiǎn)要記錄閉包的概念和一些常用的場(chǎng)景。
什么是閉包
Go函數(shù)可以是閉包。閉包是一個(gè)函數(shù)值,它從函數(shù)體外部引用變量。函數(shù)可以訪問(wèn)被引用的變量并對(duì)其賦值;從這個(gè)意義上說(shuō),函數(shù)被“綁定”到變量上。-- a Tour of Go
一個(gè)最簡(jiǎn)單的例子: 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ù)返回一個(gè)閉包。在閉包內(nèi)部,它引用了外部的變量sum。
閉包和匿名函數(shù)的區(qū)別
匿名函數(shù)是指在代碼中沒(méi)有明確命名的函數(shù),閉包是一個(gè)函數(shù)值,它可以訪問(wèn)其詞法環(huán)境中捕獲的變量。匿名函數(shù)可以是閉包,也可以不是閉包。匿名函數(shù)引用了外部作用域中的變量,它就成為閉包。
func main() {
x := 10
// 匿名函數(shù),不是閉包
anonymousFunc := func() {
fmt.Println("匿名函數(shù):", x)
}
anonymousFunc()
// 閉包
closureFunc := func() {
fmt.Println("閉包:", x)
}
closureFunc()
}
常見的應(yīng)用場(chǎng)景
閉包在實(shí)際編程中具有廣泛的應(yīng)用。以下是幾個(gè)常見的應(yīng)用場(chǎng)景:
- 保存狀態(tài): 通過(guò)捕獲外部變量,閉包可以在函數(shù)調(diào)用之間保留狀態(tài)信息,如迭代器
- 函數(shù)工廠: 根據(jù)不同的配置參數(shù)來(lái)動(dòng)態(tài)創(chuàng)建函數(shù),
- 回調(diào)函數(shù):將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),通過(guò)閉包,捕獲一些上下文信息并執(zhí)行該函數(shù)
- 并發(fā)編程:可以安全地在多個(gè)goroutine中共享和修改變量,一種簡(jiǎn)潔的方式
保存狀態(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)建一個(gè)閉包函數(shù),這個(gè)閉包函數(shù)用于迭代切片中的元素。其中,閉包每次執(zhí)行,index會(huì)遞增,直到循環(huán)結(jié)束。比如在很多開源框架的中間件中,會(huì)使用迭代器模式實(shí)現(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)建了一個(gè)閉包callback,即回調(diào)函數(shù)。在執(zhí)行異步操作時(shí),它會(huì)將計(jì)算結(jié)果result傳遞給回調(diào)函數(shù)。比如,我們需要等待某個(gè)長(zhǎng)時(shí)間的操作或者某個(gè)事件觸發(fā)之后的場(chǎng)景。
并發(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)為每個(gè)任務(wù)創(chuàng)建一個(gè)匿名函數(shù)。這些匿名函數(shù)使用閉包來(lái)捕獲循環(huán)變量i和任務(wù)函數(shù)task。在每個(gè)匿名函數(shù)內(nèi)部,我們調(diào)用任務(wù)函數(shù),并將結(jié)果存儲(chǔ)在相應(yīng)的位置。
總結(jié)
本文主要學(xué)習(xí)記錄Go語(yǔ)言中一個(gè)強(qiáng)大、極具表現(xiàn)力的特性:閉包。包括閉包的基礎(chǔ)概念,和匿名函數(shù)的區(qū)別,以及一些常見的編程場(chǎng)景。閉包因?yàn)槠潇`活性,可塑性強(qiáng),在開源庫(kù)里廣泛運(yùn)用,對(duì)提升代碼的可維護(hù)性、拓展性上有比較大的幫助。
以上就是Golang中閉包與常用場(chǎng)景詳解的詳細(xì)內(nèi)容,更多關(guān)于Go閉包的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語(yǔ)言實(shí)現(xiàn)MapReduce的示例代碼
MapReduce是一種備受歡迎的編程模型,它最初由Google開發(fā),用于并行處理大規(guī)模數(shù)據(jù)以提取有價(jià)值的信息,本文將使用GO語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的MapReduce,需要的可以參考下2023-10-10
完美解決beego 根目錄不能訪問(wèn)靜態(tài)文件的問(wèn)題
下面小編就為大家?guī)?lái)一篇完美解決beego 根目錄不能訪問(wèn)靜態(tài)文件的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
Ubuntu18.04 LTS搭建GO語(yǔ)言開發(fā)環(huán)境過(guò)程解析
這篇文章主要介紹了Ubuntu18.04 LTS搭建GO語(yǔ)言開發(fā)環(huán)境過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11

