Go十大常見錯誤第10篇:Goroutine和迴圈變數一起使用的坑

coding進階 發表於 2022-11-24
Go

前言

這是Go十大常見錯誤系列的第10篇:Goroutine和迴圈變數一起使用的坑。素材來源於Go佈道者,現Docker公司資深工程師Teiva Harsanyi

本文涉及的原始碼全部開源在:Go十大常見錯誤原始碼,歡迎大家關注公眾號,及時獲取本系列最新更新。

常見錯誤

對於Go初學者,很容易犯的一個錯誤就是goroutine和迴圈變數結合在一起使用時,錯誤地使用了迴圈變數。

比如下面這個例子:

ints := []int{1, 2, 3}
for _, i := range ints {
  go func() {
    fmt.Printf("%v\n", i)
  }()
}

這段程式的輸出結果應該是什麼?

Go初學者可能認為輸出結果應該是1 2 3,但實際情況並不是。

這個例子裡,3個goroutine共享同一個變數i,最後輸出的結果大機率是輸出3 3 3

要解決這個問題,主要有2個解決方案。

解決方案1

把迴圈變數i作為goroutine函式的一個引數,編譯器在執行go func(i int)時,就會解析到i的值,確保每個goroutine可以拿到自己想要的值。

ints := []int{1, 2, 3}
for _, i := range ints {
  go func(i int) {
    fmt.Printf("%v\n", i)
  }(i)
}

解決方案2

建立一個新的變數,用於goroutine。

ints := []int{1, 2, 3}
for _, i := range ints {
  i := i
  go func() {
    fmt.Printf("%v\n", i)
  }()
}

推薦閱讀

開源地址

文章和示例程式碼開源在GitHub: Go語言初級、中級和高階教程

公眾號:coding進階。關注公眾號可以獲取最新Go面試題和技術棧。

個人網站:Jincheng's Blog

知乎:無忌

福利

我為大家整理了一份後端開發學習資料禮包,包含程式語言入門到進階知識(Go、C++、Python)、後端開發技術棧、面試題等。

關注公眾號「coding進階」,傳送訊息 backend 領取資料禮包,這份資料會不定期更新,加入我覺得有價值的資料。還可以傳送訊息「進群」,和同行一起交流學習,答疑解惑。

References