前言
go語言中的切片,可以看作是可變化長度的數組(動態數組)。有長度(len)和容量(cap),容量必大於等於長度。
切片的結構體定義如下:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
切片的定義方式
var ( a []int // nil切片, 和 nil 相等, 一般用來表示一個不存在的切片 b = []int{} // 空切片, 和 nil 不相等, 一般用來表示一個空的集合 c = []int{1, 2, 3} // 有3個元素的切片, len和cap都為3 d = c[:2] // 有2個元素的切片, len為2, cap為3 e = c[0:2:cap(c)] // 有2個元素的切片, len為2, cap為3 f = c[:0] // 有0個元素的切片, len為0, cap為3 g = make([]int, 3) // 有3個元素的切片, len和cap都為3 h = make([]int, 2, 3) // 有2個元素的切片, len為2, cap為3 i = make([]int, 0, 3) // 有0個元素的切片, len為0, cap為3 )
遍歷
for i := range a { fmt.Printf("a[%d]: %d\n", i, a[i]) } for i, v := range b { fmt.Printf("b[%d]: %d\n", i, v) } for i := 0; i < len(c); i++ { fmt.Printf("c[%d]: %d\n", i, c[i]) }
添加元素
1.開頭添加(一般都會重新分配內存)
var a = []int{1,2,3} a = append([]int{0}, a...) // 在開頭添加1個元素 a = append([]int{-3,-2,-1}, a...) // 在開頭添加1個切片
2.末尾添加(注意:容量不足,append會重新分配內存)
var a []int a = append(a, 1) // 追加1個元素 a = append(a, 1, 2, 3) // 追加多個元素, 手寫解包方式 a = append(a, []int{1,2,3}...) // 追加一個切片, 切片需要解包
3.中間添加(append和copy組合實現)
// append實現,第二個append調用會創建一個臨時的切片 var a []int a = append(a[:i], append([]int{x}, a[i:]...)...) // 在第i個位置插入x a = append(a[:i], append([]int{1,2,3}, a[i:]...)...) // 在第i個位置插入切片 // append和copy組合實現,避免創建中間的臨時切片 a = append(a, 0) // 先擴容 copy(a[i+1:], a[i:]) // a[i:]向后移動1個位置 a[i] = x // 設置新添加的元素 // append和copy組合,在指定位置插入切片(多個元素) a = append(a, x...) // 沒有專門的函數來擴容,只有使用append copy(a[i+len(x):], a[i:]) copy(a[i:], x)
刪除元素
1.刪除元素
a := []int{1, 2, 3} // 移動數據指針 a = a[1:] // 刪除開頭1個元素 a = a[N:] // 刪除開頭N個元素 // 可以用append原地完成(所謂原地完成是指在原有的切片數據對應的內存區間內完成,不會導致內存空間結構的變化) a = append(a[:0], a[1:]...) // 刪除開頭1個元素 a = append(a[:0], a[N:]...) // 刪除開頭N個元素 // 用copy完成刪除開頭的元素 a = a[:copy(a, a[1:])] // 刪除開頭1個元素 a = a[:copy(a, a[N:])] // 刪除開頭N個元素
2.刪除尾部(最快)
a = a[:len(a)-1] // 刪除尾部1個元素
a = a[:len(a)-N] // 刪除尾部N個元素
3.刪除中間部分
// 使用append a = append(a[:i], a[i+1:]...) // 刪除中間1個元素 a = append(a[:i], a[i+N:]...) // 刪除中間N個元素 // 使用copy a = a[:i+copy(a[i:], a[i+1:])] // 刪除中間1個元素 a = a[:i+copy(a[i:], a[i+N:])] // 刪除中間N個元素
總結
切片高效操作的要點是要降低內存分配的次數,盡量保證append操作不會超出cap的容量,降低觸發內存分配的次數和每次分配內存大小。