golang 錯題集

有隻黑白貓發表於2019-12-25

簡介: 本文即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}

答案:
點選瞭解更多,檢視剩餘內容
瞭解更多

相關文章