日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

golang中的闭包

發(fā)布時(shí)間:2025/6/15 编程问答 11 豆豆
生活随笔 收集整理的這篇文章主要介紹了 golang中的闭包 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

閉包

簡(jiǎn)介

作用:縮小變量作用域,減少對(duì)全局變量的污染

閉包又是什么?你可以想象一下,在一個(gè)函數(shù)中存在對(duì)外來(lái)標(biāo)識(shí)符的引用。所謂的外來(lái)標(biāo)識(shí)符,既不代表當(dāng)前函數(shù)的任何參數(shù)或結(jié)果,也不是函數(shù)內(nèi)部聲明的,它是直接從外邊拿過(guò)來(lái)的

?

一個(gè)函數(shù)捕獲了和他在同一個(gè)作用域的其他常量和變量.這就意味著當(dāng)閉包被調(diào)用的時(shí)候,不管在程序什么地方調(diào)用,閉包能夠使用這些常量或者變量.

它不關(guān)心這些捕獲了的變量和常量是否已經(jīng)超出了作用域,所以只有閉包還在使用他,這些變量就還會(huì)存在.

在go里面,所有的匿名函數(shù)都是閉包

func main() {a := 10str := "mike"//匿名函數(shù),沒有函數(shù)名字,函數(shù)定義沒有調(diào)用f1 := func() {fmt.Println("a = ", a)fmt.Println("str = ", str)}//調(diào)用f1()//給一個(gè)函數(shù)類型起別名type FuncType func() //函數(shù)沒有參數(shù)沒有返回值//聲明變量var f2 FuncTypef2 = f1f2()//定義匿名函數(shù),同時(shí)調(diào)用func() {fmt.Printf("a = %d, str = %s\n", a, str)}() //后面的()代表調(diào)用此匿名函數(shù)//帶參數(shù)的匿名函數(shù)f3 := func(i, j int) {fmt.Printf("a = %d, str = %s\n", a, str)}f3(1, 2)//有參數(shù)有返回值x, y := func(i, j int) (max, min int) {if i > j {max = imin = j} else {max = jmin = i}return}(10, 20)fmt.Print(x, y) }

閉包以引用的方式捕獲外部變量

func main() {a := 10str := "nike"func() {a = 666str = "go"fmt.Printf("內(nèi)部: a = %d, str = %s\n", a, str)}() //()代表直接調(diào)用fmt.Printf("外部: a = %d, str =%s\n", a, str) }

輸出

內(nèi)部: a = 666, str = go 外部: a = 666, str =go

閉包保存變量

func test02() func() int {var x int //沒有初始化,值為0return func() int {x++return x * x} }func main() {//返回函數(shù)類型f := test02()fmt.Println(f())fmt.Println(f())fmt.Println(f()) }

使用

Go 函數(shù)可以是一個(gè)閉包。閉包是一個(gè)函數(shù)值,它引用了函數(shù)體之外的變量。 這個(gè)函數(shù)可以對(duì)這個(gè)引用的變量進(jìn)行訪問和賦值;換句話說(shuō)這個(gè)函數(shù)被“綁定”在這個(gè)變量上。

例如,函數(shù) adder 返回一個(gè)閉包。每個(gè)返回的閉包都被綁定到其各自的 sum 變量上。

在上面例子中(這里重新貼下代碼,和上面代碼一樣):

package mainimport "fmt"func adder() func(int) int {sum := 0return func(x int) int {sum += xreturn sum} }func main() {pos, neg := adder(), adder()for i := 0; i < 10; i++ {fmt.Println(pos(i),neg(-2*i),)} }

如pos := adder()的adder()表示返回了一個(gè)閉包,并賦值給了pos,同時(shí),這個(gè)被賦值給了pos的閉包函數(shù)被綁定在sum變量上,因此pos閉包函數(shù)里的變量sum和neg變量里的sum毫無(wú)關(guān)系。

func adder() func(int) int的func(int) int表示adder()的輸出值的類型是func(int) int這樣一個(gè)函數(shù)

沒有閉包的時(shí)候,函數(shù)就是一次性買賣,函數(shù)執(zhí)行完畢后就無(wú)法再更改函數(shù)中變量的值(應(yīng)該是內(nèi)存釋放了);有了閉包后函數(shù)就成為了一個(gè)變量的值,只要變量沒被釋放,函數(shù)就會(huì)一直處于存活并獨(dú)享的狀態(tài),因此可以后期更改函數(shù)中變量的值(因?yàn)檫@樣就不會(huì)被go給回收內(nèi)存了,會(huì)一直緩存在那里)。

比如,實(shí)現(xiàn)一個(gè)計(jì)算功能:一個(gè)數(shù)從0開始,每次加上自己的值和當(dāng)前循環(huán)次數(shù)(當(dāng)前第幾次,循環(huán)從0開始,到9,共10次),然后*2,這樣迭代10次:

沒有閉包的時(shí)候這么寫:

func abc(x int) int {return x * 2 }func main() {var a intfor i := 0; i < 10; i ++ {a = abc(a+i)fmt.Println(a)} }

如果用閉包可以這么寫:

func abc() func(int) int {res := 0return func(x int) int {res = (res + x) * 2return res} }func main() {a := abc()for i := 0; i < 10; i++ {fmt.Println(a(i))} }

2種寫法輸出值都是:

0 2 8 22 52 114 240 494 1004 2026

從上面例子可以看出閉包的3個(gè)好處:

  • 不是一次性消費(fèi),被引用聲明后可以重復(fù)調(diào)用,同時(shí)變量又只限定在函數(shù)里,同時(shí)每次調(diào)用不是從初始值開始(函數(shù)里長(zhǎng)期存儲(chǔ)變量)

    這有點(diǎn)像使用面向?qū)ο蟮母杏X,實(shí)例化一個(gè)類,這樣這個(gè)類里的所有方法、屬性都是為某個(gè)人私有獨(dú)享的。但比面向?qū)ο蟾拥妮p量化

  • 用了閉包后,主函數(shù)就變得簡(jiǎn)單了,把算法封裝在一個(gè)函數(shù)里,使得主函數(shù)省略了a=abc(a+i)這種麻煩事了

  • 變量污染少,因?yàn)槿绻麤]用閉包,就會(huì)為了傳遞值到函數(shù)里,而在函數(shù)外部聲明變量,但這樣聲明的變量又會(huì)被下面的其他函數(shù)或代碼誤改。

  • 關(guān)于閉包的第一個(gè)好處,再啰嗦舉個(gè)例子

  • 若不用閉包,則容易對(duì)函數(shù)外的變量誤操作(誤操作別人),例:
  • var A int = 1 func main() {foo := func () {A := 2fmt.Println(A)}foo()fmt.Println(A) }

    輸出:

    2 1

    如果手誤將A := 2寫成了A = 2,那么輸出就是:

    2 2

    即會(huì)影響外部變量A

  • 為了將某一個(gè)私有的值傳遞到某個(gè)函數(shù)里,就需要在函數(shù)外聲明這個(gè)值,但是這樣聲明會(huì)導(dǎo)致這個(gè)值在其他函數(shù)里也可見了(別人誤操作我),例:
  • func main() {A := 1foo := func () int {return A + 1}B := 1bar := func () int {return B + 2}fmt.Println(foo())fmt.Println(bar()) }

    輸出:

    2 3

    在bar里是可以對(duì)變量A做操作的,一個(gè)不小心就容易誤修改變量A

    **結(jié)論:函數(shù)外的變量只能通過(guò)參數(shù)傳遞進(jìn)去,不要通過(guò)全局變量的方式的渠道傳遞進(jìn)去,當(dāng)函數(shù)內(nèi)能讀取到的變量越多,出錯(cuò)概率(誤操

    總結(jié)

    以上是生活随笔為你收集整理的golang中的闭包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。