Go微服务实战
上QQ阅读APP看书,第一时间看更新

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了。