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语句带来的问题,当然,平时还是尽量避免使用指针类型的通道。

转载于:https://juejin.im/post/5c5415f76fb9a04a0a5f9e62

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值