问题代码
package main
import "fmt"
type user struct {
name string
sex uint // 1 男 0 女
}
func main() {
u := []user{
{"Jansen",1},
{"Lee",1},
{"Leo Lee",0},
}
n := make([]*user,0,len(u))
for _,v := range u{
n = append(n, &v)
}
fmt.Println(n)
for _,v := range n{
fmt.Println(v)
}
}
- 输出
[0xc0000044c0 0xc0000044c0 0xc0000044c0]
&{Leo Lee 0}
&{Leo Lee 0}
&{Leo Lee 0}
问题分析
- 用range声明的左变量v为局部变量,且仅被声明一次,变量v中的数据 切片u里成员的拷贝
- 因此&v,拿到的仅仅是该局部变量的地址,且从声明到循环结束 v的地址一直没变
- 切片遍历结束后,地址&v所存放的值是最后切片最后一个元素的值
- 因此存放局部变量指针地址的n切片的遍历会有如上输出
解决方案一
- 源切片改为指针切片
- v的值本就是指针
package main
import "fmt"
type user struct {
name string
sex uint // 1 男 0 女
}
func main() {
u := []*user{
{"Jansen",1},
{"Lee",1},
{"Leo Lee",0},
}
n := make([]*user,0,len(u))
for _,v := range u{
n = append(n, v)
}
fmt.Println(n)
for _,v := range n{
fmt.Println(v)
}
}
方案二
- 拿索引取值
package main
import "fmt"
type user struct {
name string
sex uint // 1 男 0 女
}
func main() {
u := []user{
{"Jansen",1},
{"Lee",1},
{"Leo Lee",0},
}
n := make([]*user,0,len(u))
for i,_ := range u{
n = append(n, &u[i])
}
fmt.Println(n)
for _,v := range n{
fmt.Println(v)
}
}
方案三
- 把这个引用变量v的值倒一手,赋值给一个局部变量暂存
- 防止next循环时,引用变量又变更
package main
import "fmt"
type user struct {
name string
sex uint // 1 男 0 女
}
func main() {
u := []user{
{"Jansen",1},
{"Lee",1},
{"Leo Lee",0},
}
n := make([]*user,0,len(u))
for _,v := range u{
_v := v
n = append(n, &_v)
}
fmt.Println(n)
for _,v := range n{
fmt.Println(v)
}
}
因此当你在遍历切片过程中修改数据,切记注意上述问题
package main
import "fmt"
type user struct {
name string
sex uint // 1 男 0 女
}
func main() {
u := []user{
{"Jansen",1},
{"Lee",1},
{"Leo Lee",0},
}
for i,_ := range u{
u[i].sex = 0
}
fmt.Println(u)
}