Golang中range指针数据的坑

在Golang中使用for range语句进行迭代非常的便捷,但在涉及到指针时就得小心一点了。

下面的代码中定义了一个元素类型为*int的通道ch

package main

import (
    "fmt"
)

func main() {
    ch := make(chan *int, 5)
    
    //sender
    input := []int{1,2,3,4,5}
    
    go func(){
        for _, v := range input {
            ch <- &v
        }
        close(ch)
    }()
    //receiver
    for v := range ch {
        fmt.Println(*v)
    }
}

在上面代码中,发送方将input数组发送给ch通道,接收方再从ch通道中接收数据,程序的预期输出应该是:

1
2
3
4
5

现在运行一下程序,得到的输出如下:

5
5
5
5
5

很明显,程序并没有达到预期的结果,那么问题出在哪里呢?我们将代码稍作修改:

//receiver
    for v := range ch {
        fmt.Println(v)
    }

得到如下输出:

0x416020
0x416020
0x416020
0x416020
0x416020

可以看到,5次输出变量v*int)都指向了同一个地址,返回去检查一下发送部分代码:

for _, v := range input {
    ch <- &v
}

问题正是出在这里,在for range语句中,v变量用于保存迭代input数组所得的值,但是v只被声明了一次,此后都是将迭代input出的值赋值给vv变量的内存地址始终未变,这样再将v的地址发送给ch通道,发送的都是同一个地址,当然无法达到预期效果。

解决方案是,引入一个中间变量,每次迭代都重新声明一个变量temp,赋值后再将其地址发送给ch

for _, v := range input {
    temp := v
    ch <- &temp
}

抑或直接引用数据的内存(推荐,无需开辟新的内存空间):

for k, _ := range input {
    c <- &input[k]
}

再次运行,就可看到预期的效果。以上方案是用于讨论range语句带来的问题,当然,平时还是尽量避免使用指针类型的通道。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 13,851评论 6 13
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 7,038评论 0 4
  • 文/一墨 开始的时候信心满满,走着走着就掉队了。一墨读书会有一部分孩子也是这样。 又要开始带着孩子们开始第16期共...
    河北一墨阅读 3,304评论 0 2
  • 今天阅读了《巨人的陨落》第一部,怎么说呢?我从最初的对于本书历史的不了解到现在有了一个概念。到现在我看的地方一共发...
    心情在变化阅读 2,934评论 0 0
  • 恳谈者:我的妻子丢下一对女儿给我,独自走了,我看到我两女儿没有妈妈就感觉好可怜然后就把所有的错压在自己身上,简直痛...
    梦回驼铃阅读 3,440评论 0 0