“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.