“This is the 28th day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

Go language learning

This article appears in my column:Let’s Golang

Zero, preface,

Because of the author’s weak foundation, he often encountered a lot of puzzling problems when using the Go language, so the author made up his mind to check and fill up the gaps of the Go language. This series of [Go language check and fill up the gaps and fill up the gaps] series is mainly to help the novice Gopher better understand the error-prone points, heavy and difficult points of the Go language. I hope you can like it, a little praise, pay attention to bai!

A problem with iterating over variables using the form := for range

Look at the following code and think about what the output is. Why is that?

package main
​
import (
    "fmt"
)
​
type Foo struct {
    bar string
}
​
func main(a) {
    slice1 := []Foo{
        {"A"},
        {"B"},
        {"C"},
    }
    slice2 := make([]*Foo, len(slice1))
    for index, value := range slice1 {
        slice2[index] = &value
    }
    fmt.Println(slice1[0], slice1[1], slice1[2])
    fmt.Println(slice2[0], slice2[1], slice2[2])}Copy the code

The desired result should be:

{A} {B} {C}
&{A} &{B} &{C}
Copy the code

But is this actually the case? Take a look at the output:

{A} {B} {C}
&{C} &{C} &{C}
Copy the code

Why is this happening?

Because when we iterate over variables with := in the for range loop, the index and value are reused each time, rather than creating a new memory space. So slice2 is putting in the address of value each time, so the last loop, value is {C}, and because the previous stored address is the address of value, it is storing {C}.

What’s the solution?

The first solution, of course, is to store values instead of Pointers:

package main
​
import (
    "fmt"
)
​
type Foo struct {
    bar string
}
​
func main(a) {
    slice1 := []Foo{
        {"A"},
        {"B"},
        {"C"},
    }
    slice2 := make([]Foo, len(slice1))
    for index, value := range slice1 {
        slice2[index] = value
    }
    fmt.Println(slice1[0], slice1[1], slice1[2])
    fmt.Println(slice2[0], slice2[1], slice2[2])}Copy the code
{A} {B} {C}
{A} {B} {C}
Copy the code

This is still reuse, but the value of each value is saved, not a pointer, so the output is fine. But this doesn’t look like the output we want.

So is there any other way?

package main
​
import (
    "fmt"
)
​
type Foo struct {
    bar string
}
​
func main(a) {
    slice1 := []Foo{
        {"A"},
        {"B"},
        {"C"},
    }
    slice2 := make([]*Foo, len(slice1))
    for index := range slice1 {
        slice2[index] = &slice1[index]
    }
    fmt.Println(slice1[0], slice1[1], slice1[2])
    fmt.Println(slice2[0], slice2[1], slice2[2])}Copy the code

We can say that the address of value is fixed, but the address of slice1[index] is different. We can take the address of Slice1.

The output looks like this:

{A} {B} {C}
&{A} &{B} &{C}
Copy the code

Two, multiple assignment needs to master the error point

Look at the following code, what is the output?

package main
​
import (
    "fmt"
)
​
func main(a) {
    i := 0
    s := []string{"A"."B"."C"."D"}
    i, s[i+1] = 2."Z"
    fmt.Printf("s: %v \n", s)
}
​
Copy the code

The answer is:

s: [A Z C D] 
Copy the code

Why is that?

In fact, we do multiple assignments in steps, not simultaneously, but sequentially:

The first phase is the valuation phase, followed by the implementation phase:

Such as:

a, b = b, a
Copy the code

Here’s the valuation phase:

// Valuation phase
P0 := &a; P1 := &b
R0 := a; R1 := b
Copy the code

Then there is the implementation phase:

*P0, *P1 = R0, R1
// Implementation phase
*P0 = R0
*P1 = R1
Copy the code

Assignment operations in the implementation phase do not affect the results of the valuation phase.

Furthermore, we evaluate the index or addressing expression to the left of = and then the expression to the right of =. And then we do the assignment.

So we evaluate the index expression I +1, and then we do the assignment.