簡介: 本文即Go語言的那些坑三。
本文即Go語言的那些坑三。
不要對Go併發函式的執行時機做任何假設
請看下列的列子:
1import (
2 "fmt"
3 "runtime"
4 "time"
5)
6func main(){
7 names := []string{"lily", "yoyo", "cersei", "rose", "annei"}
8 for _, name := range names{
9 go func(){
10 fmt.Println(name)
11 }()
12 }
13 runtime.GOMAXPROCS(1)
14 runtime.Gosched()
15}
請問輸出什麼?
答案:
1annei
2annei
3annei
4annei
5annei
為什麼呢?是不是有點詫異?
輸出的都是“annei”,而“annei”又是“names”的最後一個元素,那麼也就是說程式列印出了最後一個元素的值,而name對於匿名函式來講又是一個外部的值。因此,我們可以做一個推斷:雖然每次迴圈都啟用了一個協程,但是這些協程都是引用了外部的變數,當協程建立完畢,再執行列印動作的時候,name的值已經不知道變為啥了,因為主函式協程也在跑,大家並行,但是在此由於names陣列長度太小,當協程建立完畢後,主函式迴圈早已結束,所以,列印出來的都是遍歷的names最後的那一個元素“annei”。
如何證實以上的推斷呢?
其實很簡單,每次迴圈結束後,停頓一段時間,等待協程列印當前的name便可。
1import (
2 "fmt"
3 "runtime"
4 "time"
5)
6func main(){
7 names := []string{"lily", "yoyo", "cersei", "rose", "annei"}
8 for _, name := range names{
9 go func(){
10 fmt.Println(name)
11 }()
12 time.Sleep(time.Second)
13 }
14 runtime.GOMAXPROCS(1)
15 runtime.Gosched()
16}
列印結果:
1lily
2yoyo
3cersei
4rose
5annei
以上我們得出一個結論,不要對“go函式”的執行時機做任何的假設,除非你確實能做出讓這種假設成為絕對事實的保證。
假設T型別的方法上接收器既有T型別的,又有T指標型別的,那麼就不可以在不能定址的T值上呼叫T接收器的方法
請看程式碼,試問能正常編譯通過嗎?
1import (
2 "fmt"
3)
4type Lili struct{
5 Name string
6}
7func (Lili *Lili) fmtPointer(){
8 fmt.Println("poniter")
9}
10func (Lili Lili) fmtReference(){
11 fmt.Println("reference")
12}
13func main(){
14 li := Lili{}
15 li.fmtPointer()
16}
答案:
點選瞭解更多,檢視剩餘內容
瞭解更多