append
函数可以向切片中添加一个或多个元素。
当你使用append
函数向切片中添加元素时,如果切片的容量足够,那么新元素将被添加到切片的末尾,切片的长度将增加。也就是说,slice引用的底层数组不会发生变化。
如果切片的容量不足以容纳新元素,那么append
函数将创建一个新的底层数组,容量是原来的两倍(或更大),并将原切片中的元素和新元素一起复制到新数组中。然后,切片将指向新数组。slice引用的底层数组将发生变化。
我们可以让slice引用一个外部的数组来直观的看到引用数组的变化,看下面的代码:
切片容量足够的情况
// 定义一个数组
var arr [5]int = [5]int{1, 2, 3, 4, 5}
//创建一个切片,长度为5,容量为10
var slice3 []int = make([]int, 5, 10)
//取数组的部分元素
slice3 = arr[1:3]
fmt.Println("初始slice3", slice3)
slice3 = append(slice3, 200)
fmt.Println("使用了append的slice3", slice3)
//数组arr发生了变化是因为arr没有满
fmt.Println("arr发生了变化 arr:", arr)
下面是输出的结果,我们看到数组arr对应的元素发生了同步的变化,这说明在空间足够时数组引用不会发生变化。
初始slice3 [100 3]
使用了append的slice3 [100 3 200]
arr发生了变化 arr: [1 100 3 200 5]
超出了被引用数组的容量,但没有超出slice容量的情况
var arr2 [5]int = [5]int{1, 2, 3, 4, 5}
var slice2 []int = make([]int, 5, 10)
slice2 = arr2[1:]
fmt.Println("初始slice2", slice2)
slice2 = append(slice2, 200)
fmt.Println("使用了append的slice2", slice2)
//数组arr2没有变化是因为arr2已经满了
fmt.Println("arr2不再变化 arr2:", arr2)
slice2[1] = 333
fmt.Println("改变slice的值", slice2)
fmt.Println("数组arr2:", arr2)
这是输出结果,在超出了被引用数组arr2的长度之后,引用发生了变化。
之后再次修改slice的值,arr2不会发生变化,说明没有被引用。
初始slice2 [2 3 4 5]
使用了append的slice2 [2 3 4 5 200]
arr2不再变化 arr2: [1 2 3 4 5]
改变slice的值 [2 333 4 5 200]
数组arr2: [1 2 3 4 5]
当切片容量不足的情况
var arr [5]int = [5]int{1, 2, 3, 4, 5}
slice := arr[1:]
fmt.Println("初始slice", slice)
fmt.Println("slice的容量:", cap(slice))
//容量已满,append之后,slice的底层指向的数组会发生变化
//append之后,slice的底层指向的数组会发生变化
slice = append(slice, 200)
fmt.Println("使用了append添加元素的slice", slice)
slice[1] = 300
fmt.Println("改变slice的值", slice)
fmt.Println("arr没有任何变化", arr)
这一次我们直接定义一个满容量的slice,向其添加一个元素。
之后再次改变slice其中一个元素的值,被引用数组没有发生变化。
初始slice [2 3 4 5]
slice的容量: 4
使用了append添加元素的slice [2 3 4 5 200]
改变slice的值 [2 300 4 5 200]
arr没有任何变化 [1 2 3 4 5]