3.2.3 append
slice的长度是动态的,那么,若要给slice增加元素应该如何操作呢?
通过append可以在原来的切片上插入元素,可以在开头、结尾、指定位置插入元素或其他slice。
下面通过代码来看一下append的使用:
book/ch03/3.2/append/main.go
1. package main
2.
3. import "fmt"
4.
5. func main() {
6. var a = []int{1,2,3}
7. fmt.Println("cap:",cap(a))
8. a = append(a,333)
9. fmt.Println("cap:",cap(a))
10. a = append(a,[]int{-333,-333,-333,-333}...)
11. fmt.Println("cap:",cap(a))
12.
13. for i,v := range a {
14. fmt.Println(i,v)
15. }
16.
17. //可以使用append进行删除
18. a = append(a[:0],a[:3]...)//只保留前三个元素
19. for i,v := range a {
20. fmt.Println(i,v)
21. }
22. fmt.Println("cap:",cap(a))
23.
24. a = append([]int{222,222},a...)//在开头插入新的切片
25. a = append(a[:2],append([]int{-222},a[2:]...)...)//在下标2的位置插入-222
26. for i,v := range a {
27. fmt.Println(i,v)
28. }
29. fmt.Println("cap:",cap(a))
30.
31. }
32.
33. //以下是程序运行结果
34. cap: 3
35. cap: 6
36. cap: 12
37. 0 1
38. 1 2
39. 2 3
40. 3 333
41. 4 -333
42. 5 -333
43. 6 -333
44. 7 -333
45. 0 1
46. 1 2
47. 2 3
48. cap: 12
49. 0 222
50. 1 222
51. 2 -222
52. 3 1
53. 4 2
54. 5 3
55. cap: 6
第6行和第7行,使用初始值的方式定义了一个slice,打印一下切片a的容量,参考第34行的结果3,可见容量和长度是一样的。
第8行和第9行,使用append为切片a在尾部追加一个元素333。然后打印容量,结合第35行可知,容量变为了6,这是slice的自动扩容,如果发现当前的容量不足以容纳新元素,则自动扩展到原来的2倍。
第10行和第11行,向切片a追加一个新的切片,新的切片包含3个元素。然后打印一下切片a的容量,结合第36行,发现容量变为了12,是上一次容量的两倍。注意第10行函数里面的省略号,其代表可变参数,后面会介绍。
第13行至第15行,打印当前的切片a,结合第37行至第44行的结果,确认每次新增的元素都是在最后。
第18行至第22行,使用append完成一次删除,只保留前三个元素。结合第45行至第47行可以看到切片a有三个元素。第48行显示切片a的容量为12。此时,底层数组大小没有变,只是切片a的长度变了,切片a的容量并没有变。
第24行至第25行,在切片a的开头插入新的切片,有两个222元素。接着在下标为2的位置插入-222。
第26行至第28行,打印当前切片a的元素,结合第49行至第54行的结果可知,第24行和第25行的操作是成功的。
第29行,打印当前切片a的容量,第55行的结果却变为了6。难道切片除了自动扩展还可以自动收缩?不是的,之所以结果变为6,是第24行的代码造成的。仔细观察第24行的代码,它在切片a的前面插入了新的切片,这时候底层的操作是取得切片a的长度作为容量,连接到新切片的后面,发现当前容量不够,扩展容量至两倍变为6。读者可以在第24行后面自行打印容量,第24行执行完就已经变为6了。