golang中for range的取地址操作陷阱介绍

作者:qauzy 时间:2024-04-23 09:36:39 

Tips:for range创建了每个元素的副本,而不是直接返回每个元素的引用

例子1:


package main
import "fmt"
func main() {
slice := []int{0, 1, 2, 3}
myMap := make(map[int]*int)
for index, value := range slice {
 myMap[index] = &value
}
fmt.Println("=====new map=====")
prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
for key, value := range myMap {
 fmt.Printf("map[%v]=%v\n", key, *value)
}
}

输出:

dotzdeMacBook-Pro-2:src dotz$ ./range

=====new map=====

map[0]=3

map[1]=3

map[2]=3

map[3]=3

例子2:


package main  
import "fmt"  
type Test struct {
   name string
}

func (this *Test) Point() { // this  为指针
   fmt.Println(this.name)
}

func main() {  
   ts := []Test{{"a"}, {"b"}, {"c"}}
   for _, t := range ts {
       defer t.Point() //输出 c c c
   }
}

输出:

dotzdeMacBook-Pro-2:src dotz$ ./method

c

c

c

例子1 我们预期输出0,1,2,3,例子2 我们预期输出a,b, c,但两个例子的输出都不是我们预期的。

对于例子1,比较明显,执行了取地址操作,每次都取value变量的地址,所以最后map中的所有元素的值都是value变量的地址(引用),因为最后value被赋值为3,所有输出都是3.

对于例子2,隐晦一点,夹杂了defer和方法接收者的规则,但其实也和例子1一样,执行t.Point()时,得到的是t的地址(引用),for结束时,t被赋值为”c“的地址,main函数返回时,都在执行”c“的接收方法Point,所以输出都是”c".

补充:golang取地址操作采坑:for idx,item := range arr中的item是个独立对象

先看代码:


package main
import "fmt"
func main() {
   type s struct {
       A string
       B int32
   }
   arr := []s{
       {"123", 123},
       {"456", 456},
       {"789", 789},
   }
   m := make(map[string]*s)
   for idx, item := range arr {
       m[item.A] = &item
       fmt.Printf("idx=%d, addr=%p, item addr=%p\n", idx, &arr[idx], &item)
   }
   for k, v := range m {
       fmt.Printf("key=%s, v=%+v\n", k, v)
   }
}

运行输出:

idx=0, addr=0xc00004e050, item addr=0xc0000044a0

idx=1, addr=0xc00004e068, item addr=0xc0000044a0

idx=2, addr=0xc00004e080, item addr=0xc0000044a0

key=123, v=&{A:789 B:789}

key=456, v=&{A:789 B:789}

key=789, v=&{A:789 B:789}

我傻傻的在循环中取item的地址,结果所有map中的值都指向最后一个!

看来item是一个独立对象,这个对象指向了数组中的对应元素。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持asp之家。如有错误或未考虑完全的地方,望不吝赐教。

来源:https://blog.csdn.net/idwtwt/article/details/87378419

标签:golang,for,range,地址
0
投稿

猜你喜欢

  • mysql installer community 5.7.16安装详细教程

    2024-01-17 04:55:04
  • python mysql项目实战及框架搭建过程

    2024-01-21 22:51:50
  • Python可视化学习之seaborn绘制矩阵图详解

    2023-02-27 09:25:36
  • Python数学建模学习模拟退火算法旅行商问题示例解析

    2023-07-28 08:33:24
  • Python操作RabbitMQ服务器实现消息队列的路由功能

    2022-06-21 00:50:39
  • 如何根据用户银行帐户余额的多少进行显式的提交或终止?

    2009-11-22 19:28:00
  • vue 登录滑动验证实现代码

    2024-04-28 10:55:04
  • Yahoo!上的小秘密

    2007-08-23 09:48:00
  • python批量下载壁纸的实现代码

    2023-11-09 18:13:05
  • JavaScript日期工具类DateUtils定义与用法示例

    2024-04-16 08:51:29
  • PyQt5根据控件Id获取控件对象的方法

    2023-02-13 15:22:50
  • MySQL timestamp自动更新时间分享

    2024-01-22 11:48:21
  • 浅谈Go语言中字符串和数组

    2024-04-25 15:14:36
  • 重命名SQLServer数据库的方法

    2024-01-26 15:40:34
  • CSS制作滑动折叠的文字效果

    2008-12-01 13:10:00
  • OpenCV半小时掌握基本操作之色彩空间

    2021-01-05 05:27:31
  • Python实现多进程的四种方式

    2022-03-14 10:48:46
  • github配置使用指南

    2022-01-05 23:14:49
  • z-index在IE中的迷惑

    2007-05-11 16:50:00
  • pydantic进阶用法示例详解

    2022-01-31 07:00:03
  • asp之家 网络编程 m.aspxhome.com