golang中慎用slice的赋值

一篇很典型的golang slice采坑记录:https://studygolang.com/articles/6557
有如下代码:

type AutoGenerated struct {
	Age  int    `json:"age"`
	Name string `json:"name"`
	Child []int `json:"child"`
}

func main() {
	jsonStr1 := "{\"age\": 12,\"name\": \"potter\", \"child\":[1,2,3]}"
	a := AutoGenerated{}
	json.Unmarshal([]byte(jsonStr1), &a)
	aa := a.Child
	fmt.Println(aa)
	jsonStr2 := "{\"age\": 14,\"name\": \"potter\", \"child\":[3,4,5,7,8,9]}"
	json.Unmarshal([]byte(jsonStr2), &a)
	fmt.Println(aa)
}

运行会发现,第一次打印aa时,aa是 [1,2,3],第二次打印aa时,aa就变成了[3,4,5]
这是因为两次调用 unmarshal 时,a 里面的 Child 字段实际上是同一个 slice,刚开始第一次 unmarshal 时,a.Child = [1,2,3],其中 cap = 4。然后在第二次 unmarshal 时,给a.Child 中添加新的内容 [3,4,5,7,8,9] 时,因为 a.Child 的容量不足,因此需要重新分配底层array,但是因为 aa 对应的那个 slice 前4个位置已经被覆盖了,因此 aa 第二次打印的值就是 [1,2,3]了

因此,在使用slice之间的赋值时,要格外小心,因为左值和右值是使用了同一个底层array,同时它们两者何时会分拆成两个array也无法确定。
PS:用golang的切片也是公用同一个底层array

posted on 2019-10-09 21:41  daghlny  阅读(3335)  评论(0编辑  收藏  举报

导航