因为切片实际是一个指向底层数组的指针的特性。使用切片的append函数的时候需要注意一些容易引起问题的地方。切片原理可以查看之前是文章:http://blog.csdn.net/ligongxiang123/article/details/79164393
- append方法,用于给切片增加长度,如果长度超过当前切片的容量那么底层会新建一个新长度的底层数组,并将切片指向新的底层数组,并返回。如果容量并没有超过当前切片容量,那么会直接修改底层数组的对应值。
这里就引发两个问题:
如果声明了一个指明容量刚好的切片,使用循环向内部增加元素。
那么append底层的实际操作实际上会将切片的底层数组copy出N份(每超过一次就会copy一份新的底层数组),大大降低了效率和造成了内存的浪费。(append函数在遇到新增容量的时候不是采用容量值自增的方式来增加,而且采用容量翻倍、大于x长度后容量增加1/2等等算法来保证,但是如果循环过大,依然会造成性能浪费。)
如果声明了一个切片,并对其进行了一次再切片,之后对新切片append,因为是公用底层数组,因此可能造成数据污染。例如:
slice := []string {"a","b","c","d","e"}
slice2 := slice[1:2] //容量为4
slice2 = append(slice2,"f")
fmt.Println(slice) //输出:[a b f d e]
fmt.Println(slice2) //输出:[b f]
- 如果不造成污染,可以声明切片的容量,这样新增的时候就会创建一个新的底层数组,而不会污染到之前其他切片的数据。例如:
slice := []string {"a","b","c","d","e"}
slice2 := slice[1:2:2] //声明了容量为1
slice2 = append(slice2,"f")
fmt.Println(slice) //输出:[a b c d e]
fmt.Println(slice2) //输出:[b f]