内部实现
对数组进行抽象封装,可以动态增长,类似C++里面的vector。切片有 3 个字段的数据结构。分别是指向底层数组的指针、切片访问的元素的个数(即长度)和切片允许增长到的元素个数(即容量)
声明和初始化
slice := make([]string, 5)
创建一个字符串切片,其长度和容量都是 5 个元素。如果只指定长度,那么切片的容量和长度相等slice := make([]int, 3, 5)
创建一个整型切片,其长度为 3 个元素,容量为 5 个元素。无法创建一个长度大于容量的切片slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}
通过切片字面量来声明切片,长度和容量都是 5 个元素slice := []string{99: "hello"}
使用索引声明切片,使用字符串"hello"初始化第 100 个元素。长度,容量均为 100var slice []int
创建 nil 整型切片,长度,容量均为 0slice := make([]int, 0)
声明空切片。注意,不管是nil切片还是空切片,均可进行内置函数 append、 len 和 cap 的操作。跟其他语言不一样,nil切片也是可以追加元素的。
使用切片
slice[1] = 25
改变索引为 1 的元素的值- 使用切片创建切片
slice := []int{10, 20, 30, 40, 50} // 创建一个整型切片,其长度和容量都是 5 个元素 newSlice := slice[1:3] // 创建一个新切片,其长度为 2 个元素,容量为 4 个元素。注意,区间是左闭右开,所以newSlice最终值位[20, 30]。
推广开来,对底层数组容量是 cap 的切片 slice[i:j]来说,那么长度为 j - i,容量: cap - i。注意:使用切片创建的切片由于会共享底层的数组,所以此时修改新的切片会影响原来的切片。当然,在某些情况下,如果在一个slice中添加新的数据,在原有数组无法保持更多新的数据时,将导致分配一个新的数组。而现在其他的slice还指向老的数组(和老的数据),这时修改新的切片对原有的切片不会有影响。
- 使用 append 向切片增加元素,内置函数 append 也是一个可变参数的函数。这意味着可以在一次调用传递多个追加的值。可以使用...运算符将一个切片的所有元素追加到另一个切片里
// 创建一个整型切片 // 其长度和容量都是 5 个元素 slice := []int{10, 20, 30, 40, 50} // 创建一个新切片 // 其长度为 2 个元素,容量为 4 个元素 newSlice := slice[1:3] // 使用原有的容量来分配一个新元素 // 将新元素赋值为 60 newSlice = append(newSlice, 60)
slice2 := []int{0}
slice2 = append(slice2, slice...)
// slice -> {10, 20, 30, 60, 50} 由于共享底层数组,注意这个第 4 个元素变成了60
// newSlice -> {20, 30, 60}
// slice2 -> {0, 10, 20, 30, 60, 50}
* slice := source[2:3:4]
使用 3 个索引创建切片。推广开来,对于 slice[i:j:k],长度len = j - i,容量cap = k - i。注意:如果试图设置的容量比可用的容量还大,就会得到一个语言运行时错误。
## 多维切片
* slice := [][]int{ {10}, {100, 200} }
创建一个整型切片的切片
## 在函数间传递切片
在64位机器上,一个切片需要 24 字节的内存:指针字段需要 8 字节,长度和容量字段分别需要 8 字节。所以只需要传递 24 字节。
```go
// 函数 foo 接收一个整型切片,并返回这个切片
func foo(slice []int) []int {
//...
return slice
}
切片的遍历
- 传统for循环
for i := 0; i<len(slice); i++ { fmt.Println(array1[i]) }
- range表达式。注意:range 创建了每个元素的副本,而不是直接返回对该元素的引用,即改变value的值不会改变切片里面的内容。
for i, value := range slice { fmt.Println(i, value) }