Golang中range指针数据的坑
目录
在Golang中使用for range
语句进行迭代非常的便捷,但在涉及到指针时就得小心一点了。
下面的代码中定义了一个元素类型为*int
的通道ch
:
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 ch := make(chan *int, 5)
9
10 //sender
11 input := []int{1,2,3,4,5}
12
13 go func(){
14 for _, v := range input {
15 ch <- &v
16 }
17 close(ch)
18 }()
19 //receiver
20 for v := range ch {
21 fmt.Println(*v)
22 }
23}
在上面代码中,发送方将input
数组发送给ch
通道,接收方再从ch
通道中接收数据,程序的预期输出应该是:
11
22
33
44
55
现在运行一下程序,得到的输出如下:
15
25
35
45
55
很明显,程序并没有达到预期的结果,那么问题出在哪里呢?我们将代码稍作修改:
1//receiver
2for v := range ch {
3 fmt.Println(v)
4}
得到如下输出:
10x416020
20x416020
30x416020
40x416020
50x416020
可以看到,5次输出变量v
(*int
)都指向了同一个地址,返回去检查一下发送部分代码:
1for _, v := range input {
2 ch <- &v
3}
问题正是出在这里,在for range
语句中,v
变量用于保存迭代input
数组所得的值,但是v
只被声明了一次,此后都是将迭代input
出的值赋值给v
,v
变量的内存地址始终未变,这样再将v
的地址发送给ch
通道,发送的都是同一个地址,当然无法达到预期效果。
解决方案是,引入一个中间变量,每次迭代都重新声明一个变量temp
,赋值后再将其地址发送给ch
:
1for _, v := range input {
2 temp := v
3 ch <- &temp
4}
抑或直接引用数据的内存(推荐,无需开辟新的内存空间):
1for k, _ := range input {
2 c <- &input[k]
3}
再次运行,就可看到预期的效果。以上方案是用于讨论range
语句带来的问题,当然,平时还是尽量避免使用指针类型元素的通道。