使用range迭代slice遇到的坑
2022-09-09
刚接触golang迭代slice的时候遇到一个问题,其实就是传值与传值的地址问题引起的,我们先看一段代码
package main
import (
"fmt"
)
type User struct {
Id int
Name string
Vip bool
}
func main() {
users := []User{
User{Id: 1, Name: "zhangsan", Vip: true},
User{Id: 2, Name: "lisi", Vip: true},
}
vipUsers := make([]*User, 0)
for _, u := range users {
if u.Vip {
vipUsers = append(vipUsers, &u)
}
}
for _, vipUser := range vipUsers {
fmt.Printf("user: %+v \n", vipUser)
}
}
日志输出结果
user: &{Id:2 Name:lisi Vip:true}
user: &{Id:2 Name:lisi Vip:true}
是不是会有点不合符预期结果,这种问题新手最容易出现,for里面range将users迭代赋值给u局部变量,然后vipUsers slice保存的是u变量值的地址,所以vipUsers里面的元素全部是相同地址,也就是指向迭代的最后一个值。
修改片段代码可以达到我们想要的效果
for i := 0; i<len(users); i++ {
if u[i].Vip {
vipUsers = append(vipUsers, &u[i])
}
}
//or clone
for _, u := range users {
if u.Vip {
newUser := new(User)
*newUser = *&u
vipUsers = append(vipUsers, newUser)
}
}