introduce

New learners of Go may encounter common mistakes. There are two common mistakes that need to be mentioned separately. Why do I mention them separately because they are different from other languages because of the design of GO.

References to variables are used in loops (iterations)

In GO, the variables used in the loop are the same, but are assigned different values each time the loop is iterated. This is done for efficiency. However, if not used properly, it can lead to unexpected behavior.

Here’s a chestnut:

func main(a) {
	var out []*int
	for i := 0; i < 3; i++ {
		out = append(out, &i)
	}
	fmt.Println("Values:", *out[0], *out[1], *out[2])
	fmt.Println("Addresses:", out[0], out[1], out[2])}Copy the code

The above code will print:

Values: 3 3 3
Addresses: 0x40e020 0x40e020 0x40e020
Copy the code

Because each time through the loop, we’re just putting the address of variable I into the out array, because variable I is the same variable, and it only gets assigned to 3 at the end of the loop.

Solution: Declare a new variable

 for i := 0; i < 3; i++ {
	i := i // Copy i into a new variable.
 	out = append(out, &i)
 }
Copy the code

The results of

Values: 0 1 2
Addresses: 0x40e020 0x40e024 0x40e028
Copy the code

The same problem applies to slicing, because slicing itself is just an address

func main(a) {
	var out [][]int
	for _, i := range[] [1]int{{1}, {2}, {3}} {
		out = append(out, i[:])
	}
	fmt.Println("Values:", out)
}
Copy the code

Results:

Values: [[3] [3] [3]]
Copy the code

The same problem occurs when using coroutines in loops

Use loop variables in coroutines

As programmers like to use concurrency, you might write something like this: I’m so happy that concurrency in GO is so easy.

for _, val := range values {
	go func() {
    	fmt.Println(val)
	}()
}
Copy the code

However, you may find that the output is exactly the same! Because the coroutine of Go also takes a little bit of time to run, and by the end of the loop, you might not have run any goroute, and then val is actually assigned, so you’ll see that the output is the last value

Solutions:

for _, val := range values {
	go func(val interface{}) {
		fmt.Println(val)
	}(val)
}
Copy the code

Of course you can

for i := range valslice {
	val := valslice[i]
	go func(a) {
		fmt.Println(val)
	}()
}
Copy the code

Reference:github.com/golang/go/w…