前言
Go 中的for range組合可以和方便的實(shí)現(xiàn)對(duì)一個(gè)數(shù)組或切片進(jìn)行遍歷,但是在某些情況下使用for range時(shí)很可能就會(huì)被"坑",下面用一段代碼來(lái)模擬下:
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)
}
}
代碼解析:
- 創(chuàng)建一個(gè)int slice,變量名為arr1并初始化 1,2,3 作為切片的值。
- 創(chuàng)建一個(gè)*int slice,變量名為arr2。
- 通過(guò)for range遍歷arr1,然后獲取每一個(gè)元素的指針,賦值到對(duì)應(yīng)arr2中。
- 逐行打印arr2中每個(gè)元素的值。
從代碼上看,打印出來(lái)的結(jié)果應(yīng)該是
1
2
3
然而真正的結(jié)果是
3
3
3
原因
因?yàn)閒or range在遍歷值類型時(shí),其中的v變量是一個(gè)值的拷貝,當(dāng)使用獲取指針時(shí),實(shí)際上是獲取到v這個(gè)臨時(shí)變量的指針,而v變量在for range中只會(huì)創(chuàng)建一次,之后循環(huán)中會(huì)被一直重復(fù)使用,所以在arr2賦值的時(shí)候其實(shí)都是v變量的指針,而v最終會(huì)指向arr1最后一個(gè)元素的值拷貝。
來(lái)看看下面這個(gè)代碼,用for i來(lá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)
}
}
使用臨時(shí)變量
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)
}
}
官方提示
由于這一問(wèn)題過(guò)于普遍,Golang甚至將其寫入了文檔的『常見錯(cuò)誤』部分:文檔
到此這篇關(guān)于詳解Go語(yǔ)言中for range的"坑"的文章就介紹到這了,更多相關(guān)Go語(yǔ)言for range內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- golang中for range的取地址操作陷阱介紹
- Go語(yǔ)言for range(按照鍵值循環(huán))遍歷操作
- go for range遍歷二維數(shù)組的示例
- go for range坑和閉包坑的分析
- go實(shí)現(xiàn)for range迭代時(shí)修改值的操作