這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
這是 Golang官方的一個總結: SliceTricks
由於引入了內建的append的方法, 包container/vector的很多方法都被移除了,可以被內建的append和copy方法代替。
下面是棧vector的操作方法的實現,使用slice實現相關的操作。
AppendVector
Copy
1234 |
b = make([]T, len(a))copy(b, a)// 如果a不為空白,也可以用下面的方式b = append([]T(nil), a...) |
Cut
切掉一段資料
1 |
a = append(a[:i], a[j:]...) |
Delete
刪除一個元素
123 |
a = append(a[:i], a[i+1:]...)// ora = a[:i+copy(a[i:], a[i+1:])] |
Delete,但不保持原來順序
12 |
a[i] = a[len(a)-1] a = a[:len(a)-1] |
注意:如果元素是一個指標,或者是一個包含指標欄位的struct,上面的cut、delete實現可能會有潛在的記憶體流失的問題。一些元素的值可能會被a一直引用而不被釋放,下面的代碼可以解決這個問題。
Cut
12345 |
copy(a[i:], a[j:])for k, n := len(a)-j+i, len(a); k < n; k++ {a[k] = nil // or the zero value of T}a = a[:len(a)-j+i] |
Delete
123 |
copy(a[i:], a[i+1:])a[len(a)-1] = nil // or the zero value of Ta = a[:len(a)-1] |
Delete,但不保持原來順序
123 |
a[i] = a[len(a)-1]a[len(a)-1] = nila = a[:len(a)-1] |
Expand
插入一段到中間
1 |
a = append(a[:i], append(make([]T, j), a[i:]...)...) |
Extend
插入一段到尾部
1 |
a = append(a, make([]T, j)...) |
Insert
1 |
a = append(a[:i], append([]T{x}, a[i:]...)...) |
注意: 第二個append會使用它底層的儲存建立一個新的slice,然後複製a[i:]到這個slice,然後把這個slice再複製回s。 新的slice的建立和第二次copy可以使用下面的方式來避免:
Insert
123 |
s = append(s, 0)copy(s[i+1:], s[i:])s[i] = x |
InsertVector
1 |
a = append(a[:i], append(b, a[i:]...)...) |
Pop
1 |
x, a = a[len(a)-1], a[:len(a)-1] |
Push
Shift
Unshift
1 |
a = append([]T{x}, a...) |
其它技巧
無額外對象分配的filter
這個技巧利用了slice會共用它的底層的資料存放區和容量。
123456 |
b := a[:0]for _, x := range a {if f(x) {b = append(b, x)}} |
反轉
將slice中的元素反轉。
1234 |
for i := len(a)/2-1; i >= 0; i-- {opp := len(a)-1-ia[i], a[opp] = a[opp], a[i]} |
下面的代碼類似,只不過使用了兩個索引變數
123 |
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {a[left], a[right] = a[right], a[left]} |