<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
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("結果=%dn",f(1)) fmt.Printf("結果=%dn",f(20)) fmt.Printf("結果=%dn",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語言閉包的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45