前言
Go 中的for range組合可以和方便的實現對一個數組或切片進行遍歷,但是在某些情況下使用for range時很可能就會被"坑",下面用一段代碼來模擬下:
func main() {
arr1 := []int{1, 2, 3}
arr2 := make([]*int, len(arr1))
for i, v := range arr1 {
arr2[i] = v
}
for _, v := range arr2 {
fmt.Println(*v)
}
}
代碼解析:
- 創建一個int slice,變量名為arr1并初始化 1,2,3 作為切片的值。
- 創建一個*int slice,變量名為arr2。
- 通過for range遍歷arr1,然后獲取每一個元素的指針,賦值到對應arr2中。
- 逐行打印arr2中每個元素的值。
從代碼上看,打印出來的結果應該是
1
2
3
然而真正的結果是
3
3
3
原因
因為for range在遍歷值類型時,其中的v變量是一個值的拷貝,當使用獲取指針時,實際上是獲取到v這個臨時變量的指針,而v變量在for range中只會創建一次,之后循環中會被一直重復使用,所以在arr2賦值的時候其實都是v變量的指針,而v最終會指向arr1最后一個元素的值拷貝。
來看看下面這個代碼,用for i來模擬for range,這樣更易于理解:
func main() {
arr1 := []int{1, 2, 3}
arr2 := make([]*int, len(arr1))
var v int
for i:=0;ilen(arr1);i++ {
v = arr1[i]
arr2[i] = v
}
for _, v := range arr2 {
fmt.Println(*v)
}
}
解決方案
傳遞原始指針
func main() {
arr1 := []int{1, 2, 3}
arr2 := make([]*int, len(arr1))
for i := range arr1 {
arr2[i] = arr1[i]
}
for _, v := range arr2 {
fmt.Println(*v)
}
}
使用臨時變量
func main() {
arr1 := []int{1, 2, 3}
arr2 := make([]*int, len(arr1))
for i, v := range arr1 {
t := v
arr2[i] = t
}
for _, v := range arr2 {
fmt.Println(*v)
}
}
使用閉包
func main() {
arr1 := []int{1, 2, 3}
arr2 := make([]*int, len(arr1))
for i, v := range arr1 {
func(v int){
arr2[i] = v
}(v)
}
for _, v := range arr2 {
fmt.Println(*v)
}
}
官方提示
由于這一問題過于普遍,Golang甚至將其寫入了文檔的『常見錯誤』部分:文檔
到此這篇關于詳解Go語言中for range的"坑"的文章就介紹到這了,更多相關Go語言for range內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- golang中for range的取地址操作陷阱介紹
- Go語言for range(按照鍵值循環)遍歷操作
- go for range遍歷二維數組的示例
- go for range坑和閉包坑的分析
- go實現for range迭代時修改值的操作