关于Go代码中slice的append的bug
2020-08-06 本文已影响0人
迪克dike
本人某次在做code review的时候,看到类似下面这样的代码,其中有一处注释,奈何才疏学浅,看了之后感觉注释中的做法与原来的做法没有本质区别,故而亲自试验了一番,前几次简单的试验均失败了,后来就模仿源代码的方式进行构造,于是便有了下图中的代码。这样一试,果然如注释中所说,但百思不得其解,于是各种试验了一番,终于知道了原因。
func main() {
pools := [][]string{{"d", "e", "f"}, {"o", "p", "q"}}
result := [][]string{{"a", "b", "c"}}
tmpResult := make([][]string, 0)
for _, pool := range pools {
tmpResult = nil
for _, x := range result {
x1 := make([]string, len(x))
// 必须对x进行拷贝,否则在下方的循环体中, append(x, y) 将会是同一个结果
copy(x1, x)
for _, y := range pool {
tmpResult = append(tmpResult, append(x1, y))
}
}
result = tmpResult
fmt.Println("result:")
fmt.Println(result)
}
}
再来看一块儿代码
func main() {
a := make([]int, 4, 8)
copy(a, []int{1,2,3,4})
b := append(a, 5)
c := append(a, 6)
fmt.Println(b, c)
}
猜猜会输出什么?
没错,b和c都会变成 [1 2 3 4 6]
这是因为a的底层数组长度为8,b和c在append的时候都是在a的长度4的基础上进行操作的,改变的都是a底层数组的第5个元素,没错,b和c会互相影响!
那么下面这种情况呢?
func main() {
a := []int{1,2,3,4}
b := append(a, 5)
c := append(a, 6)
fmt.Println(b, c)
}
答案是:[1 2 3 4 5] [1 2 3 4 6]
好了,b是b,c是c,两者互不影响。这又是为什么呢?
因为a的长度就是4,和容量是一样的,这意味着a的底层数组的长度是4,长度超过4的数组是存不了滴,于是只能是新开辟一块儿空间,来保存新的数值啦。因为每次都是新开辟的,所以肯定是互不影响啦。就这样了,下课~