Pit detail on range pointer data in Golang

  • 2020-06-19 10:33:32
  • OfStack

preface

Iterating with for range statements in Golang is very convenient, but you have to be careful about 1 when it comes to Pointers.

The following code defines a channel ch of element type *int:


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)
 }
}

In the above code, the sender sends the input array to the ch channel, and the receiver receives the data from the ch channel. The expected output of the program should be:

Now run the program under 1, and the output is as follows:

Obviously, the program did not achieve the desired results, so what's the problem? Let's change the code a little bit:


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

The output is as follows:

[

0x416020
0x416020
0x416020
0x416020
0x416020

]

It can be seen that five times the output variable v (*int) points to the same address, and returns to check the sending part of the code under 1:


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

Problem is out of here, in for range statement, iterative input v variable used to hold the value of the income array, but v be declared only once, after all is the iterative input the value assigned to v, v variable memory address has not changed, so then v address sent to ch channel, is sent with an address, of course can't reach the expected effect.

Solutions:

An intermediate variable is introduced, and a variable temp is re-declared for each iteration, and its address is sent to ch after assignment:


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

Or directly reference the memory of the data (no need to open up new memory space, recommended) :


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

Run it again and you'll see the desired effect. The above scheme is used to discuss the problems caused by range statements, of course, in the usual way to avoid pointer type channels.

conclusion


Related articles: