Golang for range的坑
本篇參考自:https://blog.csdn.net/somanlee/article/details/107881231,尊重原創
廢話就不說了,先來一段程式碼:
package main
import (
"fmt"
)
func main() {
slice := []int{0, 1, 2, 3}
mp := make(map[int]*int)
for index, value := range slice {
mp[index] = &value
}
fmt.Println("-------------------------------------------------------------------")
for key, value := range mp {
fmt.Println(key, " ", *value)
}
}
先猜一下輸出的結果是什麼,再看看結果跟你想的是不是一樣的
沒錯,全都是 333333,就差個2了
其根本原因就是 for range是用一個變數承接rang 後面的內容,也就是上面的mp,slice,什麼意思???
我們先看看為什麼全都是3,稍微做出一點改變:
func main() {
slice := []int{0, 1, 2, 3}
mp := make(map[int]*int)
for index, value := range slice {
mp[index] = &value
fmt.Println("address is:",&value)
fmt.Println("value is:",value)
}
//根本原因在於for range是用一個變數承接mp中的內容的
fmt.Println("-------------------------------------------------------------------")
for key, value := range mp {
fmt.Println(key, " ", *value)
}
}
結果如下:
有沒有發現,為什麼地址都是一樣的,而最後這個地址的值是3,mp中存的是又是這個地址,所以不全都是3了嘛。那又為什麼會是這樣了呢?上文中的承接是什麼意思呢??
for range
for index, value := range t_slice {
original body
}
相當於:
len_temp := len(t_slice)
range_temp := t_slice
for index_temp = 0; index_temp < len_temp; index_temp++ {
value_temp := range_temp[index_temp]
index := index_temp
value := value_temp
original body
}
這個承接的變數就是 range_temp。
正確的寫法:
package main
import (
"fmt"
)
func main() {
slice := []int{0, 1, 2, 3}
mp := make(map[int]*int)
for index, value := range slice {
num := value
mp[index] = &num
// mp[index] = &slice[index] 用切片的index也行
}
//根本原因在於for range是用一個變數承接mp中的內容的
fmt.Println("-------------------------------------------------------------------")
for key, value := range mp {
fmt.Println(key, " ", *value)
}
}
在for range中啟動攜程:
package main
import (
"fmt"
"sync"
)
func main() {
var m = []int{1, 2, 3}
var wg sync.WaitGroup
for i := range m {
wg.Add(1)
go func() {
fmt.Print(i)
wg.Done()
}()
}
wg.Wait()
}
輸出結果為:222
上面的程式碼中,每輪迴圈中使用匿名函式起協程,匿名函式直接引用外部變數i,實際上,這就是golang中的閉包,閉包是匿名函式與匿名函式所引用環境的組合,匿名函式有動態建立的特性,這使得匿名函式不用通過引數傳遞的方式,就可以直接引用外部的變數。
每輪迴圈啟動一個協程,而協程啟動與迴圈變數遞增不是在同一個協程,協程啟動的速度遠小於迴圈執行的速度,所以即使是第一個協程剛起啟動時,迴圈變數可能已經遞增完畢。由於所有的協程共享迴圈變數i,而且這個i會在最後一個使用它的協程結束後被銷燬,所以最後的輸出結果都是迴圈變數的末值即2。
新增延時,確保協程啟動:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
var m = []int{1, 2, 3}
for i := range m {
wg.Add(1)
go func() {
fmt.Print(i)
wg.Done()
}()
time.Sleep(time.Second)
}
wg.Wait()
}
傳入引數:
package main
import (
"fmt"
"sync"
)
func main() {
var m = []int{1, 2, 3}
var wg sync.WaitGroup
for i := range m {
wg.Add(1)
go func(i int) {
fmt.Print(i)
wg.Done()
}(i)
}
wg.Wait()
}
區域性變數:
package main
import (
"fmt"
"sync"
)
func main() {
var m = []int{1, 2, 3}
var wg sync.WaitGroup
for i := range m {
wg.Add(1)
n := i
go func() {
fmt.Print(n)
wg.Done()
}()
}
wg.Wait()
}
每次for的時候n都是不同的變數
相關文章
- golang的踩坑Golang
- golang for range 遍歷 對比 PHP、pythonGolangPHPPython
- Golang的陣列初始化方式及for-range遍歷Golang陣列
- Dig101: Go之for-range排坑指南Go
- golang的defer踩坑彙總Golang
- Golang Recover的一個小坑Golang
- golang—踩坑之切片Golang
- Go Quiz: 從Go面試題搞懂slice range遍歷的坑GoUI面試題
- Golang 需要避免踩的 50 個坑Golang
- [golang]slice的坑:從append到共享GolangAPP
- golang最近遇到的一些坑Golang
- range 踩坑小記——為啥刪不掉資料夾?
- 使用Golang時遇到的一些坑Golang
- 踩了 Golang sync.Map 的一個坑Golang
- Golang for迴圈遍歷小坑Golang
- golang 介紹以及踩坑之四Golang
- 初學 GoLang 遇到的一個關於時間的坑...Golang
- golang連線達夢資料庫的一個坑Golang資料庫
- GO 的 range 如何使用?Go
- range與enumerate的區別
- Go 之基礎速學 (十七) golang 裡面空介面使用,型別斷言,rangeGolang型別
- HTML input rangeHTML
- Range Sparse Net
- Range Minimum Sum
- python-rangePython
- for range 作用域
- Range範圍選區的理解
- JavaScript 中的 Range 和 Selection 物件JavaScript物件
- 記一次坑爹的golang 二維map判斷問題Golang
- http斷點續傳原理:http頭 Range、Content-RangeHTTP斷點
- The Range of Application2APP
- B. Range and Partition
- for & range 效能對比
- Kotlin中的Ranges以及自定義RangeKotlin
- 基於 range 的 for 迴圈和 auto
- Range/Content-Range與斷點續傳,瞭解一下?斷點
- golang定時任務踩坑及終極解決方案Golang
- Python range() 函式用法Python函式