您的位置:首页技术文章

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

【字号: 日期:2023-09-28 10:50:02浏览:2作者:馨心

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

例子1:

package mainimport '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]=%vn', 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 mainimport '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=%pn', idx, &arr[idx], &item) } for k, v := range m { fmt.Printf('key=%s, v=%+vn', 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是一个独立对象,这个对象指向了数组中的对应元素。

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

标签: Golang
相关文章: