看如下的go程序demo
循环读取一个slice,把读取的值放入另一个slice
packagemainimport"fmt"typeFoostruct { barstring} funcmain() { list := []Foo{ {"A"}, {"B"}, {"C"}, } list2 :=make([]*Foo, len(list)) fori, value :=rangelist { //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
的内存地址,如果想得到预期的结果该怎么做
packagemainimport"fmt"typeFoostruct { barstring} funcmain() { list := []Foo{ {"A"}, {"B"}, {"C"}, } list2 :=make([]*Foo, len(list)) fori, value :=rangelist { //每次循环都重新声明一个变量temp:=valuefmt.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}
希望开发者写代码过程中,注意这个坑,不然很容易犯这个错误