欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺析Golang中閉包的創(chuàng)建與使用

 更新時(shí)間:2023年11月01日 15:52:22   作者:洛天楓  
閉包是包括?Go?在內(nèi)的編程語(yǔ)言的一項(xiàng)強(qiáng)大功能,通過(guò)閉包,您可以在函數(shù)中封裝數(shù)據(jù),并通過(guò)函數(shù)的返回值訪問(wèn)這些數(shù)據(jù),本文將介紹Go?中閉包的基礎(chǔ)知識(shí),希望對(duì)大家有所幫助

閉包是包括 Go 在內(nèi)的編程語(yǔ)言的一項(xiàng)強(qiáng)大功能。通過(guò)閉包,您可以在函數(shù)中封裝數(shù)據(jù),并通過(guò)函數(shù)的返回值訪問(wèn)這些數(shù)據(jù)。在本文中,我們將介紹 Go 中閉包的基礎(chǔ)知識(shí),包括它們是什么、如何工作以及如何有效地使用它們。

什么是閉包

go官方有一句解釋:

Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.

翻譯過(guò)來(lái)就是:

函數(shù)字面量(匿名函數(shù))是閉包:它們可以引用在周?chē)瘮?shù)中定義的變量。然后,這些變量在周?chē)暮瘮?shù)和函數(shù)字面量之間共享,只要它們還可以訪問(wèn),它們就會(huì)繼續(xù)存在。

閉包是一種創(chuàng)建函數(shù)的方法,這些函數(shù)可以訪問(wèn)在其主體之外定義的變量。閉包是一個(gè)可以捕捉其周?chē)h(huán)境狀態(tài)的函數(shù)。這意味著函數(shù)可以訪問(wèn)不在其參數(shù)列表中或在其主體中定義的變量。閉包函數(shù)可以在外部函數(shù)返回后訪問(wèn)這些變量。

在 Go 中創(chuàng)建閉包

在 Go 中,您可以使用匿名函數(shù)創(chuàng)建閉包。創(chuàng)建閉包時(shí),函數(shù)會(huì)捕獲其周?chē)h(huán)境的狀態(tài),包括外部函數(shù)中定義的任何變量。閉包函數(shù)可以在外部函數(shù)返回后訪問(wèn)這些變量。

下面是一個(gè)在 Go 中創(chuàng)建閉包的示例:

func adder() func(int) int { // 外部函數(shù)
	sum := 0
	return func(x int) int { // 內(nèi)部函數(shù)
		fmt.Println("func sum: ", sum)
		sum += x
		return sum
	}
}

func main() {
	a := adder()
	fmt.Println(a(1))
	fmt.Println(a(2))
	fmt.Println(a(3))
}

在本例中,我們定義了一個(gè)返回匿名函數(shù)的加法器函數(shù)。匿名函數(shù)捕捉加法器函數(shù)中定義的 sum 變量的狀態(tài)。每次調(diào)用匿名函數(shù)時(shí),它都會(huì)將參數(shù)加到求和變量中,并返回結(jié)果。

所以其輸出結(jié)果為:

func sum:  0
1
func sum:  1
3
func sum:  3
6

在 Go 中使用閉包

在 Go 中,閉包可用于多種用途,包括用函數(shù)封裝數(shù)據(jù)、創(chuàng)建生成器、迭代器和 memoization 函數(shù)。

下面是一個(gè)使用閉包將數(shù)據(jù)與函數(shù)封裝在一起的示例:

func makeGreeter(greeting string) func(string) string {
	return func(name string) string {
		fmt.Printf("func greeting: %s, name: %s\n", greeting, name)
		return greeting + ", " + name
	}
}

func main() {
	englishGreeter := makeGreeter("Hello")
	spanishGreeter := makeGreeter("Hola")

	fmt.Println(englishGreeter("John"))
	fmt.Println(englishGreeter("Tim"))
	fmt.Println(spanishGreeter("Juan"))
	fmt.Println(spanishGreeter("Taylor"))
}

在本例中,我們定義了一個(gè)名為 makeGreeter 的函數(shù),它返回一個(gè)匿名函數(shù)。該匿名函數(shù)接收一個(gè)字符串參數(shù),并返回一個(gè)將問(wèn)候語(yǔ)和名稱(chēng)連接起來(lái)的字符串。我們創(chuàng)建了兩個(gè)問(wèn)候語(yǔ)程序,一個(gè)用于英語(yǔ),一個(gè)用于西班牙語(yǔ),然后用不同的名稱(chēng)調(diào)用它們。

所以其輸出為:

func greeting: Hello, name: John
Hello, John
func greeting: Hello, name: Tim
Hello, Tim
func greeting: Hola, name: Juan
Hola, Juan
func greeting: Hola, name: Taylor
Hola, Taylor

替換捕獲的變量

Go 閉包的強(qiáng)大功能之一是能夠更改捕獲的變量。這使得代碼中的行為更加靈活和動(dòng)態(tài)。下面是一個(gè)例子:

func makeCounter() func() int {
	i := 0
	return func() int {
		fmt.Println("func i: ", i)
		i++
		return i
	}
}

func main() {
	counter := makeCounter()
	fmt.Println(counter())
	fmt.Println(counter())
	fmt.Println(counter())
}

在本例中,makeCounter 函數(shù)返回一個(gè)閉包,每次調(diào)用都會(huì)使計(jì)數(shù)器遞增。i 變量被閉包捕獲,并可被修改以更新計(jì)數(shù)器。

所以其輸出為:

func i:  0
1
func i:  1
2
func i:  2
3

逃逸變量

Go 閉包的另一個(gè)高級(jí)概念是變量逃逸分析。在 Go 中,變量通常在堆棧上分配,并在超出作用域時(shí)被去分配。然而,當(dāng)變量被閉包捕獲時(shí),它必須在堆上分配,以確保在函數(shù)返回后可以訪問(wèn)它。這會(huì)導(dǎo)致性能開(kāi)銷(xiāo),因此了解變量何時(shí)以及如何逃逸非常重要。

我們對(duì)比一下兩個(gè)方法:

func makeAdder1(x1 int) func(int) int {
	return func(y1 int) int {
		return x1 + y1
	}
}

func makeAdder2(x2 int) func(int) int {
	fmt.Println(x2)
	return func(y2 int) int {
		return x2 + y2
	}
}

func main() {
	a := makeAdder1(5)
	fmt.Println(a(1))

	b := makeAdder2(6)
	fmt.Println(b(1))
}

makeAdder1makeAdder2 的區(qū)別在于函數(shù)內(nèi)的 x 是否被使用。

而我們通過(guò)逃逸分析:

go build -gcflags "-m" main.go

會(huì)得到以下輸出:

./main.go:5:6: can inline makeAdder1
./main.go:6:9: can inline makeAdder1.func1
./main.go:13:9: can inline makeAdder2.func1
./main.go:12:13: inlining call to fmt.Println
./main.go:19:17: inlining call to makeAdder1
./main.go:6:9: can inline main.makeAdder1.func1
./main.go:20:15: inlining call to main.makeAdder1.func1
./main.go:20:13: inlining call to fmt.Println
./main.go:23:13: inlining call to fmt.Println
./main.go:6:9: func literal escapes to heap
./main.go:12:13: ... argument does not escape
./main.go:12:14: x2 escapes to heap
./main.go:13:9: func literal escapes to heap
./main.go:19:17: func literal does not escape
./main.go:20:13: ... argument does not escape
./main.go:20:15: ~R0 escapes to heap
./main.go:23:13: ... argument does not escape
./main.go:23:15: b(1) escapes to heap

從逃逸分析結(jié)果來(lái)看,x 變量被閉包捕獲,必須在堆上分配。不過(guò),如果 x 變量不被閉包之外的任何其他代碼使用,編譯器可以進(jìn)行優(yōu)化,將其分配到棧中。

共享閉包

最后,Go 中的閉包可以在多個(gè)函數(shù)之間共享,從而實(shí)現(xiàn)更高的靈活性和模塊化代碼。下面是一個(gè)例子:

type Calculator struct {
	add func(int, int) int
}

func NewCalculator() *Calculator {
	c := &Calculator{}
	c.add = func(x, y int) int {
		fmt.Printf("func x: %d, y: %d\n", x, y)
		return x + y
	}
	return c
}

func (c *Calculator) Add(x, y int) int {
	return c.add(x, y)
}

func main() {
	calc := NewCalculator()
	fmt.Println(calc.Add(1, 2))
	fmt.Println(calc.Add(2, 3))
}

在本例中,Calculator 結(jié)構(gòu)具有一個(gè) add 函數(shù),該函數(shù)在 NewCalculator 函數(shù)中通過(guò)閉包進(jìn)行了初始化。Calculator 結(jié)構(gòu)的 Add 方法只需調(diào)用 add 函數(shù),這樣就可以在多個(gè)上下文中重復(fù)使用。

所以其輸出為:

func x: 1, y: 2
3
func x: 2, y: 3
5

結(jié)論

在 Go 編程中,閉包是一個(gè)強(qiáng)大的工具,可用于用函數(shù)封裝數(shù)據(jù),并創(chuàng)建生成器和迭代器等。它們提供了一種訪問(wèn)函數(shù)體外定義的變量的方法,即使在函數(shù)返回后也是如此。

到此這篇關(guān)于淺析Golang中閉包的創(chuàng)建與使用的文章就介紹到這了,更多相關(guān)go閉包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語(yǔ)言學(xué)習(xí)之反射的用法詳解

    Go語(yǔ)言學(xué)習(xí)之反射的用法詳解

    反射指的是運(yùn)行時(shí)動(dòng)態(tài)的獲取變量的相關(guān)信息。本文將為大家詳細(xì)介紹Go語(yǔ)言中反射的用法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-04-04
  • Go語(yǔ)言kylin任務(wù)自動(dòng)化實(shí)例詳解

    Go語(yǔ)言kylin任務(wù)自動(dòng)化實(shí)例詳解

    這篇文章主要為大家介紹了Go語(yǔ)言kylin任務(wù)自動(dòng)化實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Gin與Mysql實(shí)現(xiàn)簡(jiǎn)單Restful風(fēng)格API實(shí)戰(zhàn)示例詳解

    Gin與Mysql實(shí)現(xiàn)簡(jiǎn)單Restful風(fēng)格API實(shí)戰(zhàn)示例詳解

    這篇文章主要為大家介紹了Gin與Mysql實(shí)現(xiàn)簡(jiǎn)單Restful風(fēng)格API示例詳解,有需要的朋友可以借鑒參考下希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11
  • 一文總結(jié)Go語(yǔ)言切片核心知識(shí)點(diǎn)和坑

    一文總結(jié)Go語(yǔ)言切片核心知識(shí)點(diǎn)和坑

    都說(shuō)Go的切片用起來(lái)絲滑得很,Java中的List怎么用,切片就怎么用,作為曾經(jīng)的Java選手,因?yàn)榍衅氖褂貌坏卯?dāng),喜提缺陷若干,本文就給大家總結(jié)一下Go語(yǔ)言切片核心知識(shí)點(diǎn)和坑,需要的朋友可以參考下
    2023-06-06
  • golang 64位linux環(huán)境下編譯出32位程序操作

    golang 64位linux環(huán)境下編譯出32位程序操作

    這篇文章主要介紹了golang 64位linux環(huán)境下編譯出32位程序操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 關(guān)于Golang獲取當(dāng)前項(xiàng)目絕對(duì)路徑的問(wèn)題

    關(guān)于Golang獲取當(dāng)前項(xiàng)目絕對(duì)路徑的問(wèn)題

    這篇文章主要介紹了Golang獲取當(dāng)前項(xiàng)目絕對(duì)路徑的問(wèn)題,通常的做法是go run用于本地開(kāi)發(fā),用一個(gè)命令中快速測(cè)試代碼確實(shí)非常方便;在部署生產(chǎn)環(huán)境時(shí),我們會(huì)通過(guò)go build構(gòu)建出二進(jìn)制文件然后上傳到服務(wù)器再去執(zhí)行,那么會(huì)產(chǎn)生什么問(wèn)題呢?感興趣的朋友一起看看吧
    2022-04-04
  • Go語(yǔ)言小白入門(mén)刷題打印輸出沙漏

    Go語(yǔ)言小白入門(mén)刷題打印輸出沙漏

    這篇文章主要介紹了Go語(yǔ)言刷題打印輸出沙漏的示例過(guò)程詳解,非常適合剛?cè)腴T(mén)Go語(yǔ)言的小白學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • Go語(yǔ)言庫(kù)系列之flag的具體使用

    Go語(yǔ)言庫(kù)系列之flag的具體使用

    這篇文章主要介紹了Go語(yǔ)言庫(kù)系列之flag的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • go語(yǔ)言實(shí)現(xiàn)markdown解析庫(kù)的方法示例

    go語(yǔ)言實(shí)現(xiàn)markdown解析庫(kù)的方法示例

    這篇文章主要介紹了go語(yǔ)言實(shí)現(xiàn)markdown解析庫(kù)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • go語(yǔ)言?nil使用避坑指南

    go語(yǔ)言?nil使用避坑指南

    這篇文章主要為大家介紹了go語(yǔ)言?nil使用避坑指南詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09

最新評(píng)論