SkillAgentSearch skills...

SliceTricks

Перевод https://github.com/golang/go/wiki/SliceTricks

Install / Use

/learn @Konstantin8105/SliceTricks
About this skill

Quality Score

0/100

Supported Platforms

Universal

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.

Вот векторные операции и их аналоги манипуляций со срезами:

Добавление вектора

a = append(a, b...)

Копирование

b = make([]T, len(a))
copy(b, a)
// или
b = append([]T(nil), a...)

Вырезание

a = append(a[:i], a[j:]...)

Удаление

a = append(a[:i], a[i+1:]...)
// или
a = a[:i+copy(a[i:], a[i+1:])]

Удалить без сохранения расположения

a[i] = a[len(a)-1]
a = a[:len(a)-1]

Замечание

Если тип элемента - это указатель или struct с полями указателя, которые должны быть собраны в сборщиком мусора, то вышеупомянутые реализации Cut и Delete имеют потенциальную проблему с утечкой памяти: некоторые элементы со значениями все еще ссылаются на срез a и, следовательно, не могут быть собраны. Следующий код может решить эту проблему:

Вырезание

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]

Удаление

copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]

Удалить без сохранения расположения

a[i] = a[len(a)-1]
a[len(a)-1] = nil
a = a[:len(a)-1]

Расширение

a = append(a[:i], append(make([]T, j), a[i:]...)...)

Расширение нулевыми значениями

a = append(a, make([]T, j)...)

Вставка

a = append(a[:i], append([]T{x}, a[i:]...)...)

Замечание

Второй append создает новый срез со своим собственным базовым хранилищем и копирует элементы в a[i:] на этот фрагмент, и эти элементы затем копируются обратно на срез a(первым append). Создание нового фрагмента (и, следовательно, сборкой мусора) и второй копии можно избежать, используя альтернативный способ:

Вставка

s = append(s, 0)
copy(s[i+1:], s[i:])
s[i] = x

Вставка вектора

a = append(a[:i], append(b, a[i:]...)...)

Взятие первого значения и смещение среза на 1 элемент в начале

x, a = a[0], a[1:]

Взятие последнего значения и смещение среза на 1 элемент в конце

x, a = a[len(a)-1], a[:len(a)-1]

Добавление в конец среза

a = append(a, x)

Добавление в начало среза

a = append([]T{x}, a...)

Дополнительные трюки

Фильтрация без аллоцирования памяти

Этот трюк использует тот факт, что срез имеет тот же базовый массив и емкость, что и оригинал, поэтому хранилище повторно используется для фильтрованного фрагмента. Конечно, исходное содержимое изменяется.

b := a[:0]
for _, x := range a {
	if f(x) {
		b = append(b, x)
	}
}
View on GitHub
GitHub Stars5
CategoryDevelopment
Updated10mo ago
Forks0

Security Score

67/100

Audited on Jun 3, 2025

No findings