详解Go语言中for range的"坑"
前言
Go中的forrange组合可以和方便的实现对一个数组或切片进行遍历,但是在某些情况下使用forrange时很可能就会被"坑",下面用一段代码来模拟下:
funcmain(){ arr1:=[]int{1,2,3} arr2:=make([]*int,len(arr1)) fori,v:=rangearr1{ arr2[i]=&v } for_,v:=rangearr2{ fmt.Println(*v) } }
代码解析:
- 创建一个intslice,变量名为arr1并初始化1,2,3作为切片的值。
- 创建一个*intslice,变量名为arr2。
- 通过forrange遍历arr1,然后获取每一个元素的指针,赋值到对应arr2中。
- 逐行打印arr2中每个元素的值。
从代码上看,打印出来的结果应该是
1
2
3
然而真正的结果是
3
3
3
原因
因为forrange在遍历值类型时,其中的v变量是一个值的拷贝,当使用&获取指针时,实际上是获取到v这个临时变量的指针,而v变量在forrange中只会创建一次,之后循环中会被一直重复使用,所以在arr2赋值的时候其实都是v变量的指针,而&v最终会指向arr1最后一个元素的值拷贝。
来看看下面这个代码,用fori来模拟forrange,这样更易于理解:
funcmain(){ arr1:=[]int{1,2,3} arr2:=make([]*int,len(arr1)) varvint fori:=0;i解决方案
传递原始指针
funcmain(){ arr1:=[]int{1,2,3} arr2:=make([]*int,len(arr1)) fori:=rangearr1{ arr2[i]=&arr1[i] } for_,v:=rangearr2{ fmt.Println(*v) } }使用临时变量
funcmain(){ arr1:=[]int{1,2,3} arr2:=make([]*int,len(arr1)) fori,v:=rangearr1{ t:=v arr2[i]=&t } for_,v:=rangearr2{ fmt.Println(*v) } }使用闭包
funcmain(){ arr1:=[]int{1,2,3} arr2:=make([]*int,len(arr1)) fori,v:=rangearr1{ func(vint){ arr2[i]=&v }(v) } for_,v:=rangearr2{ fmt.Println(*v) } }官方提示
由于这一问题过于普遍,Golang甚至将其写入了文档的『常见错误』部分:文档
到此这篇关于详解Go语言中forrange的"坑"的文章就介绍到这了,更多相关Go语言forrange内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!