for i,v:=range切片,v地址会变吗?介绍一些forrange踩坑点。

for i,v:=range切片,v地址会变吗?

1.22之后,在Golang中range遍历切片v的地址是会变的,但是这个v是临时变量,打印的地址不是原数组的地址。

	sc := []int{1, 2, 3, 4, 5}
	for _, v := range sc {
		fmt.Println(&v)
	}
	fmt.Println("----")
	for i := 0; i < len(sc); i++ {
		fmt.Println(&sc[i])
	}

输出结果:

0xc00000a0d8
0xc00000a110
0xc00000a118
0xc00000a120
0xc00000a128
----
0xc00000e3f0
0xc00000e3f8
0xc00000e400
0xc00000e408
0xc00000e410

可见原切片和临时变量v的地址不同,切片中相邻元素地址可能不连续是因为在Go语言中由于内存对齐、内存池分配、垃圾回收等造成的。

在1.22之前for range遍历切片地址是不变的,就是临时变量v的地址。

	sc := []int{1, 2, 3, 4, 5}
	var a []*int
	for _, v := range sc {
		fmt.Println(&v)
		a = append(a, &v)
	}
	fmt.Println(*a[0], *a[1], *a[2], *a[3])

这个可以自己测试一下,我这个版本是go version go1.23.0 windows/amd64,如果是1.22之前的可以试一试。

介绍一些forrange踩坑点。

1.使用迭代变量时的闭包问题

	funcs := make([]func(), 0, 10)
	for i := 0; i < 5; i++ {
		funcs = append(funcs, func() {
			fmt.Println(i)
		})
	}

	for _, f := range funcs {
		f()
	}

输出结果:

0
1
2
3
4

在这里并没有什么问题,但是在1.22版本前的,可能出现问题输出结果都是6,因为在之前匿名函数中使用循环中的i是引用,所以在forrange时全部打印最后的值,但是在1.22之后这个就修改了,目前正常输出。

2.修改切片中的元素

// 错误代码
	sc := []int{0, 1, 2, 3, 4}
	for _, v := range sc {
		v = 20
	}
	fmt.Println(sc)

以上使用直接提示不可以这样使用,如果要想修改切片某个元素,使用索引来修改。

3.遍历字典无序

字典forrange遍历无序。

如果我想让字典遍历有序呢?

那就让key排序,然后在依次输出数据。

	mp := map[string]string{"b": "你好", "a": "你们好", "c": "大家都好"}
	keys := make([]string, 0, len(mp))
	for k := range mp {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, i := range keys {
		fmt.Println(i, mp[i])
	}

4.字符串遍历

	s := "你们好啊"
	for i, v := range s {
		fmt.Println(i, string(v))
	}

输出结果:

0 你
3 们
6 好
9 啊

for range遍历字符串,每次迭代返回Unicode代码点,而不是字节。遍历字符串建议用常规for循环。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

席万里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值