SoFunction
Updated on 2025-03-05

Detailed explanation of Golang's common errors in value copy and single variable in for loop

Preface

golang (Chinese name: go language) is the second open source programming language released by Google in 2009. Go language is specially optimized for the programming of multiprocessor system applications. Programs compiled with Go can be comparable to the speed of C or C++ code, and are more secure and support parallel processes. . If you want to know more, please move to the official websitegolang official website

In Go, the call to a function is a copy value of the value, and the variable of v is always a variable in the for loop. If v is a pointer, print method receives a copy of the pointer, and the pointer value of v in each iteration in the for loop body is different, so the output is different.

In the Common Go Error Article/gotchas-and-common-mistakes-in-go-golang/There is a piece of code like this:

package main

import ( 
 "fmt"
 "time"
)

type field struct { 
 name string
}

func (p *field) print() { 
 ()
}

func main() { 
 data := []field{{"one"},{"two"},{"three"}}

 for _,v := range data {
 go ()
 }

 (3 * )
 //goroutines print: three, three, three
}

Change the type of field slice to pointer and the result is different:

package main

import ( 
 "fmt"
 "time"
)

type field struct { 
 name string
}

func (p *field) print() { 
 ()
}

func main() { 
 data := []*field{{"one"},{"two"},{"three"}}

 for _,v := range data {
 v := v
 go ()
 }

 (3 * )
 //goroutines print: one, two, three
}

How exactly does the difference between these two codes lead to the difference in the results?

I have modified the part of the code above for loop, and the corresponding codes after the transformation are:

slice right or wrong pointer

 data := []field{{"one"},{"two"},{"three"}}

 for _,v := range data {
 pp := (*field).print
 go pp(&v) //Not pointer }

slice is a pointer

 data := []*field{{"one"},{"two"},{"three"}}

 for _,v := range data {
 pp := (*field).print
 go pp(v) // pointer
 }

After the transformation, you can see the most obvious difference when you look at the original code.

In Go, the call to a function is a copy value of the value, and the variable of v is always a variable in the for loop.

If v is a pointer, print method receives a copy of the pointer, and the pointer value of v in each iteration in the for loop body is different, so the output is different.

If v is an ordinary struct, every iteration in the for loop body &v is the pointer of the variable v itself, that is, it always points to the same field. Since to a large extent, the goroutine in this code is executed after the end of for, and at this time v will point to the last field, that is, {"three"}, the output is the same.

Some people say that the random output of one, two, and three is caused by the reason that the CPU is multi-core. If it is changed to a single core, it will be output sequentially. This statement is not particularly accurate. Theoretically, the scheduling of goroutines is somewhat random, that is, even single-core output may be random. However, when running such a simple example, the general machine environment will not cause cross-execution of these 3 simple goroutines. For example, you can simulate io busyness before print output to achieve the purpose of even a single core that may be random output.

 if (100) > 20 {
 (1 * )
 }

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.