关于for range中只存最后一个元素的问题

本文详细探讨了Go语言中for-range循环在处理切片和映射时的特性,揭示了为何在某些情况下遍历后的映射元素值会全部相同。通过例子分析,指出for-range在每次迭代时创建的是值的副本,而非原始元素的引用,导致最后存储的是循环结束时的值。同时,对比了for循环和for-range在处理同样情况时的不同行为,加深了对Go语言内存管理和范围迭代的理解。
摘要由CSDN通过智能技术生成

例1

m := make(map[int]*int)
    arr := []int{1, 2, 3, 4, 5}
    for i, v := range arr {
        m[i] = &v
    }
    for k, v := range m {
        fmt.Println("k-->v", k, *v)
    }

运行结果

map是无序的,我们指关注value,value的值都是5,这时候是否有疑问,循环存储了arr,为什么结果都是5

先了解一下range的特性

for range每次都是拷贝原变量的副本,也就是值拷贝

在上面的例子中,我们拷贝并不是 arr[i]对应的地址,而是变量v的地址,v只是一个临时变量

我们修改代码再看

func main() {
	m := make(map[int]*int)
	//m1 := make(map[int]*int)
	arr := []int{1, 2, 3, 4, 5}
	for i, v := range arr {
		m[i] = &v
		fmt.Println(&v)
		fmt.Println(*m[i])
	}

 运行结果

0xc0000140d8
1
0xc0000140d8
2
0xc0000140d8
3
0xc0000140d8
4
0xc0000140d8
5

 我们可以看到v的地址是不变的,变的是值

所以我们在例1中看到m每次存储的都是v的地址,看下面的代码,我们打印一下m

    m := make(map[int]*int)
	arr := []int{1, 2, 3, 4, 5}
	for i, v := range arr {
		m[i] = &v
	} 
	fmt.Println(m)

 运行结果

map[0:0xc0000140d8 1:0xc0000140d8 2:0xc0000140d8 3:0xc0000140d8 4:0xc0000140d8]
k-->v 4 5
k-->v 3 5
k-->v 0 5
k-->v 1 5
k-->v 2 5

 我们可以看到map元素地址都是一样的

那么就可以解释为什么都是元素都是5了,因为for range最后循环完毕,地址中的值是5,所以我们循环map,里面的值也都是5

例2

我们修改切片中的元素添加6,再次运行

    m := make(map[int]*int)
	arr := []int{1, 2, 3, 4, 5, 6}
	for i, v := range arr {
		m[i] = &v
	} 
	fmt.Println(m)
	for k, v := range m {
		fmt.Println("k-->v", k, *v)
	}
map[0:0xc0000140d8 1:0xc0000140d8 2:0xc0000140d8 3:0xc0000140d8 4:0xc0000140d8 5:0xc0000140d8]
k-->v 5 6
k-->v 0 6
k-->v 1 6
k-->v 2 6
k-->v 3 6
k-->v 4 6

 里面的值都变成6了,这是因为range完毕最后一个值是6,所以循环遍历map只是打印的那个地址里面的值而已

总结

for range中value只是一个临时变量,是一个固定的地址,值是不断改变的,而且这个地址只存range完毕的最后一个值

接for和range比较

不妨再看一下for循环

func main() {
	m := make(map[int]*int)
	m1 := make(map[int]*int)
	arr := []int{1, 2, 3, 4, 5, 6}
	for i, v := range arr {
		m[i] = &v
	}
	for i := 0; i < len(arr); i++ {
		m1[i] = &arr[i]	
	}
	fmt.Println(m1)
	fmt.Println(m)
	for k, v := range m {
		fmt.Println("m:k-->v", k, *v)
	}
	for k, v := range m1 {
		fmt.Println("m1:k-->v", k, *v)
	}
}
map[0:0xc0000c0060 1:0xc0000c0068 2:0xc0000c0070 3:0xc0000c0078 4:0xc0000c0080 5:0xc0000c0088]
map[0:0xc0000aa058 1:0xc0000aa058 2:0xc0000aa058 3:0xc0000aa058 4:0xc0000aa058 5:0xc0000aa058]
m:k-->v 0 6
m:k-->v 1 6
m:k-->v 2 6
m:k-->v 3 6
m:k-->v 4 6
m:k-->v 5 6
m1:k-->v 0 1
m1:k-->v 1 2
m1:k-->v 2 3
m1:k-->v 3 4
m1:k-->v 4 5
m1:k-->v 5 6

 有不对的地方请指正,蟹蟹!

参考:【golang】 关于for range中只存储最后一个元素的问题 - 要坚持的girl - 博客园

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值