https://jnnctechnologies.com/ |
Go makes the distinction between passing objects by value and by reference explicit. Let's start with example 1 [1]:
func foobyval(n int) {
fmt.Println(n)
}
func main() {
for i := 0; i < 5; i++ {
go foobyval(i)
}
time.Sleep(100 * time.Millisecond)
}
It should come as no surprise that this will print out the values 0 to 4, likely in some scrambled order. So we'll move on to example 2:
func foobyref(n *int) {
fmt.Println(*n)
}
func main() {
for i := 0; i < 5; i++ {
go foobyref(&i)
}
time.Sleep(100 * time.Millisecond)
}
This is going to print:
5
5
5
5
5
Understanding why will take us 80% of the way to grokking the main topic of this post, so let's spend some time exploring this.
It turns out that the answer is right there in the Go spec, which states:
Variables declared by the init statement are re-used in each iteration.
This means that when the program is running, there's just a single object representing i, not a new one for each iteration. This object gets assigned a new value on each iteration.
Let's study the difference in the generated machine code [2] for the for loop between examples 1 and 2. Starting with example 1:
0x0021 00033 (go-func-byval.go:13) MOVQ AX, "".i+24(SP)
0x0026 00038 (go-func-byval.go:14) MOVL $8, (SP)
0x002d 00045 (go-func-byval.go:14) LEAQ "".foobyval·f(SB), CX
0x0034 00052 (go-func-byval.go:14) MOVQ CX, 8(SP)
0x0039 00057 (go-func-byval.go:14) MOVQ AX, 16(SP)
0x003e 00062 (go-func-byval.go:14) CALL runtime.newproc(SB)
0x0043 00067 (go-func-byval.go:13) MOVQ "".i+24(SP), AX
0x0048 00072 (go-func-byval.go:13) INCQ AX
0x004b 00075 (go-func-byval.go:13) CMPQ AX, $5
0x004f 00079 (go-func-byval.go:13) JLT 33
0 Comments
If you have any doubts,please let me know