https://github.com/konstantin8105/slicetricks
Перевод https://github.com/golang/go/wiki/SliceTricks
https://github.com/konstantin8105/slicetricks
go golang slice slice-tricks tricks
Last synced: about 1 year ago
JSON representation
Перевод https://github.com/golang/go/wiki/SliceTricks
- Host: GitHub
- URL: https://github.com/konstantin8105/slicetricks
- Owner: Konstantin8105
- Created: 2018-04-18T13:57:45.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2018-04-18T14:20:18.000Z (about 8 years ago)
- Last Synced: 2025-01-23T06:14:30.766Z (over 1 year ago)
- Topics: go, golang, slice, slice-tricks, tricks
- Size: 3.91 KB
- Stars: 4
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Трюки со срезами(SliceTricks)
Перевод https://github.com/golang/go/wiki/SliceTricks
Axel Wagner edited this page on Feb 4 · 29 revisions
Поскольку введена встроенная команда `append`, большая часть функциональности пакета `container/vector`, было удалено в Go 1, но ёё функциональность можно реализовать с помощью команд `append` и` copy`.
Вот векторные операции и их аналоги манипуляций со срезами:
#### Добавление вектора
```go
a = append(a, b...)
```
#### Копирование
```go
b = make([]T, len(a))
copy(b, a)
// или
b = append([]T(nil), a...)
```
#### Вырезание
```go
a = append(a[:i], a[j:]...)
```
#### Удаление
```go
a = append(a[:i], a[i+1:]...)
// или
a = a[:i+copy(a[i:], a[i+1:])]
```
#### Удалить без сохранения расположения
```go
a[i] = a[len(a)-1]
a = a[:len(a)-1]
```
**Замечание**
Если тип элемента - это *указатель* или struct с полями указателя, которые должны быть собраны в сборщиком мусора, то вышеупомянутые реализации `Cut` и `Delete` имеют потенциальную проблему с утечкой *памяти*: некоторые элементы со значениями все еще ссылаются на срез `a` и, следовательно, не могут быть собраны. Следующий код может решить эту проблему:
> **Вырезание**
```go
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]
```
> **Удаление**
```go
copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]
```
> **Удалить без сохранения расположения**
```go
a[i] = a[len(a)-1]
a[len(a)-1] = nil
a = a[:len(a)-1]
```
#### Расширение
```go
a = append(a[:i], append(make([]T, j), a[i:]...)...)
```
#### Расширение нулевыми значениями
```go
a = append(a, make([]T, j)...)
```
#### Вставка
```go
a = append(a[:i], append([]T{x}, a[i:]...)...)
```
**Замечание**
Второй `append` создает новый срез со своим собственным базовым хранилищем и копирует элементы в `a[i:]` на этот фрагмент, и эти элементы затем копируются обратно на срез `a`(первым `append`). Создание нового фрагмента (и, следовательно, сборкой мусора) и второй копии можно избежать, используя альтернативный способ:
> **Вставка**
```go
s = append(s, 0)
copy(s[i+1:], s[i:])
s[i] = x
```
#### Вставка вектора
```go
a = append(a[:i], append(b, a[i:]...)...)
```
#### Взятие первого значения и смещение среза на 1 элемент в начале
```go
x, a = a[0], a[1:]
```
#### Взятие последнего значения и смещение среза на 1 элемент в конце
```go
x, a = a[len(a)-1], a[:len(a)-1]
```
#### Добавление в конец среза
```go
a = append(a, x)
```
#### Добавление в начало среза
```go
a = append([]T{x}, a...)
```
## Дополнительные трюки
### Фильтрация без аллоцирования памяти
Этот трюк использует тот факт, что срез имеет тот же базовый массив и емкость, что и оригинал, поэтому хранилище повторно используется для фильтрованного фрагмента. Конечно, исходное содержимое изменяется.
```go
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
```