简单地说,切片就相当于一种简化版的动态数组。结构定义如下:
type SliceHeader struct {
Data uintptr //执行底层数组的指针
Len int //切片当前长度
Cap int //切片容量
}
跟字符串比较就是多了一个容量Cap字段,它表示的是切片指向的内存空间的最大容量(对应元素个数而不是字节数),len也是指元素个数。
切片用法如下:
package main
import "fmt"
func main() {
//切片定义
var (
a []int //[] len:0 cap:0
b = []int{} //[] len:0 cap:0
c = []int{1,2,3} //[1 2 3] len:3 cap:3
d = c[0:2] //[1 2] len:2 cap:3
e = c[0:2:cap(c)]//[1 2] len:2 cap:3
f = c[:0] //[] len:0 cap:3
g = make([]int ,3) //[0 0 0] len:3 cap:3
h = make([]int, 2, 3)//[0 0] len:2 cap:3
i = make([]int, 0, 3)//[] len:0 cap:3
)
println(a == nil)//true
println(b == nil)//false
// 切片后面附加
var sli []int
sli = append(sli, 1)
sli = append(sli, 1, 2, 3)
sli = append(sli, []int{1,2,3}...) //... 切片解包
// 切片前面附加
sli = append([]int{1,2,3}, sli...)
// 切片中间附加
sli = append(sli, []int{1,2,3}...) //切片扩容
copy(sli[4:], sli[1:]) //copy(target,source) 索引1和其后的元素后移3位
copy(sli[1:], []int{1,2,3})
// 切片元素删除
sli = sli[:len(sli) - 2] //删除后两个元素
sli = sli[2:]//删除前两个元素 移动数据指针
sli = append(sli[:0], sli[2:]...)//删除前两个元素,不移动数据指针
// copy完成切片头两个元素删除
copy(sli[:0], sli[2:])
sli = sli[:len(sli)-2] //等同于sli = sli[:copy(sli[:0], sli[2:])]
//copy()函数的返回值表示实际发生复制的元素个数
}
append()函数返回一个新切片,不影响参数。copy()函数返回实际发生复制的元素个数,目标参数会发生变化。
切片高效操作的要点是要降低内存分配的次数,尽量保证append()操作不会超出cap的容量。