看如下的go程式demo
循環讀取一個slice,把讀取的值放入另一個slice
package main
import "fmt"
type Foo struct {
bar string
}
func main() {
list := []Foo{
{"A"},
{"B"},
{"C"},
}
list2 := make([]*Foo, len(list))
for i, value := range list {
//fmt.Printf("%p\n",&value)
list2[i] = &value
}
fmt.Println(list[0], list[1], list[2])
fmt.Println(list2[0], list2[1], list2[2])
}
理想中的預期運作結果應該是
{A} {B} {C}
&{A} &{B} &{C}
但是當你實際運作後,結果不是這樣了
{A} {B} {C}
&{C} &{C} &{C}
為什麼是這樣的結果呢?
首先我們應該知道,
for
循環中,初始變量會被重用,例如:
i
,
value
,在
for
之前被配置設定記憶體位址,之後循環隻是一直對這個記憶體位址重新指派,我們可以把代碼注釋去掉看看執行結果
0xc0001041e0
0xc0001041e0
0xc0001041e0
{A} {B} {C}
&{C} &{C} &{C}
從執行結果中,可以看到記憶體位址一樣,而在for循環最後元素時,
value
的值是
C
,而
&value
是一個指向
value
的記憶體位址,如果想得到預期的結果該怎麼做
package main
import "fmt"
type Foo struct {
bar string
}
func main() {
list := []Foo{
{"A"},
{"B"},
{"C"},
}
list2 := make([]*Foo, len(list))
for i, value := range list {
//每次循環都重新聲明一個變量
temp:=value
fmt.Printf("%p\n",&temp)
list2[i] = &temp
}
fmt.Println(list[0], list[1], list[2])
fmt.Println(list2[0], list2[1], list2[2])
}
運作結果
0xc0001041e0
0xc0001041f0
0xc000104200
{A} {B} {C}
&{A} &{B} &{C}
希望開發者寫代碼過程中,注意這個坑,不然很容易犯這個錯誤