詳解Go語(yǔ)言中for range的"坑"
前言
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;i<len(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)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go?interface?接口的最佳實(shí)踐經(jīng)驗(yàn)分享
go?的接口在go的編程里面用的十分頻繁,尤其是空接口的使用,因?yàn)橛辛私涌?,才使得Go語(yǔ)言變得異常的強(qiáng)大,今天給大家介紹下Go?interface?接口的最佳實(shí)踐經(jīng)驗(yàn)分享,感興趣的朋友一起看看吧2022-04-04Golang 定時(shí)器的終止與重置實(shí)現(xiàn)
在實(shí)際開發(fā)過(guò)程中,我們有時(shí)候需要編寫一些定時(shí)任務(wù)。很多人都熟悉定時(shí)器的使用,那么定時(shí)器應(yīng)該如何終止與重置,下面我們就一起來(lái)了解一下2021-08-08GO語(yǔ)言實(shí)現(xiàn)TCP服務(wù)器的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)GO語(yǔ)言實(shí)現(xiàn)TCP服務(wù)器,文中的示例代碼講解詳細(xì),對(duì)我們深入了解Go語(yǔ)言有一定的幫助,需要的可以參考一下2023-03-03Go+Redis緩存設(shè)計(jì)與優(yōu)化實(shí)現(xiàn)
本文主要介紹了Go+Redis緩存設(shè)計(jì)與優(yōu)化實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-02-02Go項(xiàng)目與Docker結(jié)合實(shí)現(xiàn)高效部署深入探究
在現(xiàn)代軟件開發(fā)中,使用Docker部署應(yīng)用程序已經(jīng)成為一種標(biāo)準(zhǔn)實(shí)踐,本文將深入探討如何將Go項(xiàng)目與Docker結(jié)合,實(shí)現(xiàn)高效、可靠的部署過(guò)程,通過(guò)詳細(xì)的步驟和豐富的示例,你將能夠迅速掌握這一流程2023-12-12Ruby序列化和持久化存儲(chǔ)(Marshal、Pstore)操作方法詳解
這篇文章主要介紹了Ruby序列化和持久化存儲(chǔ)(Marshal、Pstore)操作方法詳解,包括Ruby Marshal序列化,Ruby Pstore存儲(chǔ),需要的朋友可以參考下2022-04-04