詳解Go語言中for range的"坑"
前言
Go 中的for range組合可以和方便的實現(xiàn)對一個數(shù)組或切片進行遍歷,但是在某些情況下使用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)
}
}
代碼解析:
- 創(chuàng)建一個int slice,變量名為arr1并初始化 1,2,3 作為切片的值。
- 創(chuàng)建一個*int slice,變量名為arr2。
- 通過for range遍歷arr1,然后獲取每一個元素的指針,賦值到對應(yīng)arr2中。
- 逐行打印arr2中每個元素的值。
從代碼上看,打印出來的結(jié)果應(yīng)該是
1
2
3
然而真正的結(jié)果是
3
3
3
原因
因為for range在遍歷值類型時,其中的v變量是一個值的拷貝,當使用&獲取指針時,實際上是獲取到v這個臨時變量的指針,而v變量在for range中只會創(chuàng)建一次,之后循環(huán)中會被一直重復(fù)使用,所以在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;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)
}
}
使用臨時變量
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甚至將其寫入了文檔的『常見錯誤』部分:文檔
到此這篇關(guān)于詳解Go語言中for range的"坑"的文章就介紹到這了,更多相關(guān)Go語言for range內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go?singleflight緩存雪崩源碼分析與應(yīng)用
這篇文章主要為大家介紹了go?singleflight緩存雪崩源碼分析與應(yīng)用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
Go語言之io.ReadAtLeast函數(shù)的基本使用和原理解析
io.ReadAtLeast函數(shù)是Go語言標準庫提供的一個工具函數(shù),能夠從數(shù)據(jù)源讀取至少指定數(shù)量的字節(jié)數(shù)據(jù)到緩沖區(qū)中,這篇文章主要介紹了io.ReadAtLeast函數(shù)的相關(guān)知識,需要的朋友可以參考下2023-07-07
Go初學(xué)者踩坑之go?mod?init與自定義包的使用
go?mod是go的一個模塊管理工具,用來代替?zhèn)鹘y(tǒng)的GOPATH方案,下面這篇文章主要給大家介紹了關(guān)于Go初學(xué)者踩坑之go?mod?init與自定義包的使用,需要的朋友可以參考下2022-10-10

