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

 更新时间:2021年04月26日 08:32:58   作者:qauzy  
这篇文章主要介绍了golang中for range的取地址操作陷阱,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

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是一个独立对象,这个对象指向了数组中的对应元素。

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

相关文章

  • Golang sync.Once实现单例模式的方法详解

    Golang sync.Once实现单例模式的方法详解

    Go 语言的 sync 包提供了一系列同步原语,其中 sync.Once 就是其中之一。本文将深入探讨 sync.Once 的实现原理和使用方法,帮助大家更好地理解和应用 sync.Once,需要的可以参考一下
    2023-05-05
  • Go1.18新特性工作区模糊测试及泛型的使用详解

    Go1.18新特性工作区模糊测试及泛型的使用详解

    这篇文章主要为大家介绍了Go 1.18新特性中的工作区 模糊测试 泛型使用进行详细讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Go归并排序算法的实现方法

    Go归并排序算法的实现方法

    归并排序采用的也是分治的策略,把原本的问题先分解成一些小问题进行求解,再把这些小问题各自的答案修整到一起得到原本问题的答案,从而达到分而治之的目的,对Go归并排序算法相关知识感兴趣的朋友一起看看吧
    2022-04-04
  • 初步解读Golang中的接口相关编写方法

    初步解读Golang中的接口相关编写方法

    这篇文章主要介绍了Golang中的接口相关编写方法,是Go语言入门学习中的基础知识,需要的朋友可以参考下
    2015-11-11
  • Go语言Gin处理响应方式详解

    Go语言Gin处理响应方式详解

    gin框架封装了常用的数据格式方法响应于客户端,下面这篇文章主要给大家介绍了关于Go语言Gin处理响应方式的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • 深入解析Go语言中上下文超时与子进程管理

    深入解析Go语言中上下文超时与子进程管理

    这篇文章小编将通过一个实际问题的案例,和大家深入探讨一下Go语言中的上下文超时和子进程管理,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-10-10
  • 更高效的GoLevelDB:shardingdb实现分片和并发读写操作

    更高效的GoLevelDB:shardingdb实现分片和并发读写操作

    这篇文章主要介绍了更高效的GoLevelDB:shardingdb实现分片和并发读写操作的相关资料,需要的朋友可以参考下
    2023-09-09
  • Golang WebView跨平台的桌面应用库的使用

    Golang WebView跨平台的桌面应用库的使用

    Golang WebView是一个强大的桌面应用库,本文介绍了Golang WebView的特点和使用方法,并列举示例详细的介绍了其在实际项目中的应用,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Golang实现Json分级解析及数字解析实践详解

    Golang实现Json分级解析及数字解析实践详解

    你是否遇到过在无法准确确定json层级关系的情况下对json进行解析的需求呢?本文就来和大家介绍一次解析不确定的json对象的经历,以及遇到的问题和解决方法
    2023-02-02
  • 浅析Go中fasthttp与net/http的性能对比及应用

    浅析Go中fasthttp与net/http的性能对比及应用

    这篇文章主要为大家详细介绍了Golang中fasthttp的底层实现以及与net/http的区别,下面就跟随小编一起来看看fasthttp到底是如何做到性能如此之快的吧
    2024-03-03

最新评论