您好,登錄后才能下訂單哦!
這篇文章主要介紹“Go語言中的閉包實例分析”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Go語言中的閉包實例分析”文章能幫助大家解決問題。
1.全局變量在main函數執行之前初始化,全局可見
2.局部變量在函數內部或者if、for等語句塊有效,使用之后外部不可見
3.全局變量和局部變量同名的情況下,局部變量生效。
4.可見性:
包內任何變量或函數都是能訪問的。
包外的話,首字母大寫是可以訪問的,首字母小寫的表示私有的不能被外部調用。
1.Go語言中函數也是一種類型,所以可以用一個函數類型的變量進行接收。
func anonyTest1(){ fmt.Println("anonyTest1") } //將改函數賦值給一個變量f,執行f func AnonyTest(){ f:= anonyTest1 f() }
2.匿名函數就是不指定名稱的函數,如下就是匿名函數的使用
func AnonyTest2(){ f:= func() { fmt.Println("AnonyTest2") } f() //或者 func() { fmt.Println("AnonyTest2...") }() }
3.下面一個例子結合defer來看一下,這三個輸出都是什么
func AnonyTest3(){ var i=0 defer func() { fmt.Printf("defer func i=%v \n",i) }() defer fmt.Printf("defer i=%v \n",i) for;i<10; i++{ } fmt.Printf("i=%v \n",i) }
從defer那篇文章我們知道 defer fmt.Printf("defer i=%v \n",i) 打印的就是i初始化后的值,最后一個也一定是for循環之后的值10,
主要就是匿名函數執行之后的值,有意思是10,說明訪問了匿名函數外部的i,這就涉及到了閉包
運行結果如下:
i=10
defer i=0
defer func i=10
4.既然函數也是一種類型,那么就可以把函數當做參數進行輸入、輸出了。(感覺有點類似C#里面的委托)
func Calc(a,b int, op func(int,int)int) int { return op(a,b) } func add(a,b int) int{ return a+b } func sub(a,b int)int{ return a-b } func AnonyTest4(){ var a = 2 var b = 1 var x = Calc(a,b,add) var y = Calc(a,b,sub) fmt.Printf("x=%v, y=%v \n",x,y) }
結果:
x=3, y=1
閉包是由函數和與其相關的引用環境組合而成的實體(好抽象,難理解啊)
func Adder() func(int) int{ var x int return func(d int) int{ x+=d return x } }
像上面這段代碼,我們可以看到定義了一個變量x,以及return中的匿名函數。我們可以看到匿名函數引用了外部的變量x,我們可以把這個x叫做自由變量。
換句話說,這個匿名函數和這個自由變量x組成了一個整體,只要是在這個整體的生命周期內這個x都是有效的。
下面使用一下這個Adder函數:
func ClosureDemo5(){ var f = Adder() fmt.Printf("結果=%d\n",f(1)) fmt.Printf("結果=%d\n",f(20)) fmt.Printf("結果=%d\n",f(300)) }
執行結果
結果=1
結果=21
結果=321
正如上面所提到的,這個只要Addr() 也就是f這個對象沒有消亡,那么f中的這個x就始終存在,也就是為什么第二次是21,第三次是321的原因了。
例子1:
func Adder2(base int) func(int)int{ return func(i int) int{ base += i return base } } func main(){ tmp1 := Adder2(10) fmt.Println(tmp1(1),tmp1(2)) tmp2 := Adder2(100) fmt.Println(tmp2(10),tmp2(20)) }
這里Adder2接收一個int類型參數base,然后返回一個func,這里這個匿名函數里面引用了這個參數base,那么這個參數base和匿名函數就形成了一個整體。
后面我們 tmp1被賦值為 Adder2(10) ,那么在tmp1這個對象的生命周期內,base是被初始化為10且一直存在,所以結果是 11 和 13,同理后面是 110 和 130
例子2:
func calc(base int) (func(int)int,func(int)int){ add:= func(i int)int{ base +=i return base } sub:= func(i int)int{ base -= i return base } return add,sub } func main(){ f1,f2 := calc(10) fmt.Println(f1(1),f2(2)) fmt.Println(f1(3),f2(4)) fmt.Println(f1(5),f2(6)) fmt.Println(f1(7),f2(8)) }
分析一下:
這里base和 add以及sub的匿名函數也組成了一個實體也就是calc,所以在f1和f2的生命周期內,base一直存在,并被初始化成了10.
所以結果就是 f1(1) 就是10+1 =11 而 f2(2)就是 11-2 = 9,其他同理。
所以結果如下:
11 9
12 8
13 7
14 6
func main(){ for i:=0;i<5;i++{ go func(x int){ fmt.Println(x) }(i) } time.Sleep(time.Second) }
上述代碼應該結果是多少?我的猜想應該是0、1、2、3、4
但是實際結果是:
5
5
5
5
5
為什么會出現這樣的情況?實際上面這里每一個go協程中的匿名函數和外部for循環的i也形成了閉包,因為for循環執行比較快,所以go還沒來得及執行就變成5了。
我在每一個go協程之后加一個延時,結果就是0,1,2,3,4了。
func main(){ for i:=0;i<5;i++{ go func(){ fmt.Println(i) }() time.Sleep(time.Second) } time.Sleep(time.Second) }
結果如下
0
1
2
3
4
問題就在于不可能每次執行都進行延遲吧,所以需要做一件事情打破這個閉包。
func main(){ for i:=0;i<5;i++{ go func(x int){ fmt.Println(x) }(i) } time.Sleep(time.Second) }
這里把i當做參數傳入到匿名函數中,保證了每次循環傳的值都不一樣。
關于“Go語言中的閉包實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。