Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame^] | 1 | Since the introduction of the ` append ` built-in, most of the functionality of the ` container/vector ` package, which was removed in Go 1, can be replicated using ` append ` and ` copy `. |
| 2 | |
| 3 | Here are the vector methods and their slice-manipulation analogues: |
| 4 | |
| 5 | ` AppendVector ` |
| 6 | ``` |
| 7 | a = append(a, b...) |
| 8 | ``` |
| 9 | ` Copy ` |
| 10 | ``` |
| 11 | b = make([]T, len(a)) |
| 12 | copy(b, a) |
| 13 | // or |
| 14 | b = append([]T(nil), a...) |
| 15 | ``` |
| 16 | ` Cut ` |
| 17 | ``` |
| 18 | a = append(a[:i], a[j:]...) |
| 19 | ``` |
| 20 | ` Delete ` |
| 21 | ``` |
| 22 | a = append(a[:i], a[i+1:]...) |
| 23 | // or |
| 24 | a = a[:i+copy(a[i:], a[i+1:])] |
| 25 | ``` |
| 26 | ` Delete without preserving order ` |
| 27 | ``` |
| 28 | a[i], a = a[len(a)-1], a[:len(a)-1] |
| 29 | ``` |
| 30 | **NOTE** If the type of the element is a _pointer_ or a struct with pointer fields, which need to be garbage collected, the above implementations of ` Cut ` and ` Delete ` have a potential _memory leak_ problem: some elements with values are still referenced by slice ` a ` and thus can not be collected. The following code can fix this problem: |
| 31 | > ` Cut ` |
| 32 | ``` |
| 33 | copy(a[i:], a[j:]) |
| 34 | for k, n := len(a)-j+i, len(a); k < n; k ++ { |
| 35 | a[k] = nil // or the zero value of T |
| 36 | } // for k |
| 37 | a = a[:len(a)-j+i] |
| 38 | ``` |
| 39 | > ` Delete ` |
| 40 | ``` |
| 41 | copy(a[i:], a[i+1:]) |
| 42 | a[len(a)-1] = nil // or the zero value of T |
| 43 | a = a[:len(a)-1] |
| 44 | ``` |
| 45 | > ` Delete without preserving order ` |
| 46 | ``` |
| 47 | a[i], a[len(a)-1], a = a[len(a)-1], nil, a[:len(a)-1] |
| 48 | ``` |
| 49 | |
| 50 | ` Expand ` |
| 51 | ``` |
| 52 | a = append(a[:i], append(make([]T, j), a[i:]...)...) |
| 53 | ``` |
| 54 | ` Extend ` |
| 55 | ``` |
| 56 | a = append(a, make([]T, j)...) |
| 57 | ``` |
| 58 | |
| 59 | ` Insert ` |
| 60 | ``` |
| 61 | a = append(a[:i], append([]T{x}, a[i:]...)...) |
| 62 | ``` |
| 63 | **NOTE** The second ` append ` creates a new slice with its own underlying storage and copies elements in ` a[i:] ` to that slice, and these elements are then copied back to slice ` a ` (by the first ` append `). The creation of the new slice (and thus memory garbage) and the second copy can be avoided by using an alternative way: |
| 64 | > ` Insert ` |
| 65 | ``` |
| 66 | s = append(s, 0) |
| 67 | copy(s[i+1:], s[i:]) |
| 68 | s[i] = x |
| 69 | ``` |
| 70 | |
| 71 | ` InsertVector ` |
| 72 | ``` |
| 73 | a = append(a[:i], append(b, a[i:]...)...) |
| 74 | ``` |
| 75 | ` Pop ` |
| 76 | ``` |
| 77 | x, a = a[len(a)-1], a[:len(a)-1] |
| 78 | ``` |
| 79 | ` Push ` |
| 80 | ``` |
| 81 | a = append(a, x) |
| 82 | ``` |
| 83 | |
| 84 | ## Additional Tricks |
| 85 | ### Filtering without allocating |
| 86 | |
| 87 | This trick uses the fact that a slice shares the same backing array and capacity as the original, so the storage is reused for the filtered slice. Of course, the original contents are modified. |
| 88 | |
| 89 | ``` |
| 90 | b := a[:0] |
| 91 | for _, x := range a { |
| 92 | if f(x) { |
| 93 | b = append(b, x) |
| 94 | } |
| 95 | } |
| 96 | ``` |