话不多说,咱们直接上问题,先看一段代码:
//随便定义的,当个例子
type Item struct {
key int
}
func main() {
var all []*Item
items := []Item{
{key: 1},
{key: 2},
{key: 3},
{key: 4},
}
for _, v := range items {
all = append(all, &v)
}
fmt.Printf("%v", all)
}
大家可以先看看最后printf应该输出什么?好了,答案揭晓
[0xc0000aa078 0xc0000aa078 0xc0000aa078 0xc0000aa078]
为什么all中保存的是同一个地址呢,这个地址指向的数据是什么?那我们重新打印一遍
for _, v := range all {
fmt.Printf("%v, %p\n", *v, v)
}
//Output:
/*
{4}, 0xc0000aa078
{4}, 0xc0000aa078
{4}, 0xc0000aa078
{4}, 0xc0000aa078
*/
我们发现,此时all中保存的都是最后一个Item,我们明明是for-range遍历切片,为什么会是这种结果?
那我们再换一种方式,我们先不进行append,我们就单纯的遍历一下
type Item struct {
key int
}
func main() {
var all []*Item
items := []Item{
{key: 1},
{key: 2},
{key: 3},
{key: 4},
}
for _, v := range items {
fmt.Printf("%v, %p\n", v, &v)
}
}
//Output:
//{1}, 0xc0000aa058
//{2}, 0xc0000aa058
//{3}, 0xc0000aa058
//{4}, 0xc0000aa058
从结果发现,数据是正确的,但是每次遍历时v的地址却都是一样的。为了便于我们观察,我们更详细的打印一下
for i, v := range items {
fmt.Printf("%p, %v, %p\n", &items[i], v, &v)
}
//Output:
// 0xc0000a8080, {1}, 0xc0000aa058
// 0xc0000a8088, {2}, 0xc0000aa058
// 0xc0000a8090, {3}, 0xc0000aa058
// 0xc0000a8098, {4}, 0xc0000aa058
情况已经很清晰了,第一个地址&items[i]不同这是正确的,遍历出的值{1}、{2}、{3}、{4}这也没有毛病,只有v的地址是相同的这一点让人疑惑
那我们可以大胆猜想一下,是不是for-range在遍历时每次循环创建的v都是同一个,然后再将每次循环到的数据保存到这个v中
type Item struct {
key int
}
func main() {
var all []*Item
items := []Item{
{key: 1},
{key: 2},
{key: 3},
{key: 4},
}
for _, v := range items {
all = append(all, &v)
}
fmt.Printf("%v", all)
}
此时我们回到最开始的问题,由于在for-range遍历时创建的v是同一个v,那么在将其添加到指针切片中后,保存的都是每次循环最后一个值,这也就是为什么all中保存的值地址相同且数据都是遍历切片的最后一个