[toc]
copy 的问题
使用 range 的时候如果我们直接修改它返回的数据会不生效,因为返回的数据并不是原始数据:
type account struct {
balance float32
}
accounts := []account{
{balance: 100.},
{balance: 200.},
{balance: 300.},
}
for _, a := range accounts {
a.balance += 1000
}
如果像上面这么做,那么输出的 accounts 是:
[{100} {200} {300}]
所以我们想要改变 range 中的数据可以这么做:
for i := range accounts {
accounts[i].balance += 1000
}
range slice 的话也会 copy 一份:
s := []int{0, 1, 2}
for range s {
s = append(s, 10)
}
这份代码在 range 的时候会 copy 一份,因此只会调用三次 append 后停止。
指针问题
比方我们想要 range slice 并将返回值存到 map 里面供后面业务使用,类似这样:
type Customer struct {
ID string
Balance float64
}
test := []Customer{
{ID: "1", Balance: 10},
{ID: "2", Balance: -10},
{ID: "3", Balance: 0},
}
var m map[string]*Customer
for _, customer := range test {
m[customer.ID] = &customer
}
但是这样遍历 map 里面存的并不是我们想要的,你会发现存的 value 都是最后一个:
{"1":{"ID":"3","Balance":0},"2":{"ID":"3","Balance":0},"3":{"ID":"3","Balance":0}}
这是因为当我们使用 range 遍历 slice 的时候,返回的 customer 变量实际上是一个固定的地址:
for _, customer := range test {
fmt.Printf("%p\n", &customer) //我们想要获取这个指针的时候
}
输出:
0x1400000e240
0x1400000e2400x1400000e240
这是因为迭代器会把数据都放入到 0x1400000e240 这块空间里面:
所以我们可以这样在 range 里面获取指针:
for _, customer := range test {
current := customer // 使用局部变量
fmt.Printf("%p\n", ¤t) // 这里获取的指针是 range copy 出来元素的指针
}
或者:
for i := range test {
current := &test[i] // 使用局部变量
fmt.Printf("%p\n", current)
}