3.2.2 基本操作
首先来了解一下slice的定义:
s := []int{1,2,3,4,5}
如果在方括号[]中指定了长度或者写入了省略号,那么这就是一个数组。
如果只是想创建一个slice而不赋值,那么可以使用make函数进行操作。示例如下:
ss := make([]int,10)
上面的示例通过make函数定义了[]int类型的切片,长度为10。定义时可以设定第三个参数(容量),本例留空,默认取长度10。对于数组元素,由于没有设定具体的初始值,因此元素都会取对应元素类型int的初始默认值0。
可以使用range方式遍历ss切片:
for i,v := range ss{ fmt.Println(i,v) }
运行后输出的值都是0,而下标是从0到9,证明make分配了一块内存空间。
如果想主动释放slice的空间,可以通过为它赋值nil实现:
ss = nil
接下来看一下切片的基本操作:
book/ch03/3.2/slicebase/main.go
1. package main
2.
3. import "fmt"
4.
5. func main() {
6. a := [...]int{1,2,3,4,5}
7. ss := a[1:3]
8. fmt.Println(a)
9. fmt.Println(ss)
10. ss[0] = 666
11. ss[1] = -666
12. fmt.Println(a)
13. fmt.Println(ss)
14. }
15.
16. //以下是上述代码的执行结果
17. [1 2 3 4 5]
18. [2 3]
19. [1 666 -666 4 5]
20. [666 -666]
第6行定义了一个数组,注意,是数组不是切片。
第7行定义了一个切片,将a[1]作为ss切片的第一个元素,长度为2。然后打印数组和切片,可以在第17行和第18行看到结果。
第10行至第11行对切片的元素重新赋值,然后分别打印数组a和切片ss。结合第19行和第20行可以看到,对于切片的操作不仅影响了切片本身,也影响了数组。可知ss切片其实是指向数组a的引用。
下面通过图3-2来解释ss和a的关系。
可以看到,切片的data是指向起始元素的指针,而长度根据赋值时的开始和结束下标进行推测。容量是从起始元素到数组最后一个元素的元素个数,可以通过cap函数取得,读者可以自行通过cap函数查看ss的容量,这里看到的是4。打印ss容量的语句如下:
fmt.Println(cap(ss))
说明
不管是数组还是切片都可以以s[i:j](0<=i<=j<=cap(s))的方式进行操作,注意每次取元素都是左闭右开的,而且i和j都是默认值,如果不写i,默认为0;如果不写j,默认为cap(s)。所以s[:]就是整个s。
注意
上一节内容专门强调了用数组作为函数形参要注意使用指针,而slice就不存在这个问题,slice传递的本就是地址(严格来说是reflect.SliceHeader),不会复制值,对切片的操作也会直接影响原来的数组或切片。