Iterating over in Golang using the for range statement is very convenient, but you have to be careful when it comes to Pointers.
The following code defines a channel ch whose element type is *int:
package main
import (
"fmt"
)
func main(a) {
ch := make(chan *int.5)
//sender
input := []int{1.2.3.4.5}
go func(a){
for _, v := range input {
ch <- &v
}
close(ch)
}()
//receiver
for v := range ch {
fmt.Println(*v)
}
}
Copy the code
In the above code, the sender sends the input array to the CH channel, and the receiver receives data from the CH channel. The expected output of the program should be:
One, two, three, four, fiveCopy the code
Now run the program and get the following output:
5, 5, 5, 5Copy the code
Clearly, the program didn’t deliver the expected results, so what went wrong? Let’s change the code slightly:
//receiver
for v := range ch {
fmt.Println(v)
}
Copy the code
We get the following output:
0x416020
0x416020
0x416020
0x416020
0x416020
Copy the code
The output variable v (*int) refers to the same address five times.
for _, v := range input {
ch <- &v
}
Copy the code
In the for range statement, the v variable is used to hold the value of the iterated input array, but v is only declared once. Thereafter, the iterated input value is assigned to V, and the memory address of the V variable remains the same. Thus, the address of V is sent to the CH channel, always at the same address. Of course it didn’t work.
The solution is to introduce an intermediate variable, redeclare a variable temp with each iteration, and then send its address to CH:
for _, v := range input {
temp := v
ch <- &temp
}
Copy the code
Or refer directly to the memory of the data (no new memory is recommended) :
for k, _ := range input {
c <- &input[k]
}
Copy the code
Run it again, and you’ll see the desired effect. The above scheme is to discuss the problems caused by the range statement, of course, in normal times to avoid using pointer type channels.