Слайсы
Слайс — гибкая обёртка над массивом
Слайс не хранит данные сам — он ссылается на backing array. Под капотом это три поля:
┌─────────┬─────┬─────┐
│ ptr │ len │ cap │
└─────────┴─────┴─────┘
ptr— указатель на первый элемент в backing arraylen— сколько элементов видно через слайсcap— сколько элементов доступно до конца backing array
Создание слайса
// Литерал — создаёт backing array сразу
s := []int{1, 2, 3, 4, 5}
// make — задаём len и cap явно
s2 := make([]int, 3) // len=3, cap=3
s3 := make([]int, 3, 10) // len=3, cap=10
// nil-слайс — нулевое значение, len=0, cap=0
var s4 []int
fmt.Println(s4 == nil) // true
fmt.Println(len(s4)) // 0 — безопасно использоватьappend
append добавляет элементы в конец слайса:
s := []int{1, 2, 3}
s = append(s, 4) // [1 2 3 4]
s = append(s, 5, 6, 7) // [1 2 3 4 5 6 7]
s = append(s, []int{8, 9}...) // развернуть слайсЕсли len == cap, append выделяет новый backing array (обычно в 2× больше) и копирует данные:
s := make([]int, 3, 3)
fmt.Printf("ptr=%p cap=%d\n", s, cap(s)) // ptr=X cap=3
s = append(s, 99)
fmt.Printf("ptr=%p cap=%d\n", s, cap(s)) // ptr=Y cap=6 — новый массив!Поэтому всегда пиши s = append(s, ...) — результат может быть новым слайсом.
Подслайсы
s := []int{0, 1, 2, 3, 4, 5}
a := s[1:4] // [1 2 3], len=3, cap=5
b := s[:3] // [0 1 2]
c := s[3:] // [3 4 5]Подслайс делит backing array с оригиналом:
a[0] = 99
fmt.Println(s) // [0 99 2 3 4 5] — оригинал изменился!copy
Чтобы получить независимую копию:
src := []int{1, 2, 3, 4, 5}
dst := make([]int, len(src))
copy(dst, src)
dst[0] = 99
fmt.Println(src) // [1 2 3 4 5] — не изменилсяcopy возвращает количество скопированных элементов — минимум из len(dst) и len(src).
Удаление элемента
В Go нет встроенного delete для слайса. Классический паттерн:
s := []int{1, 2, 3, 4, 5}
i := 2 // удаляем элемент с индексом 2
s = append(s[:i], s[i+1:]...)
fmt.Println(s) // [1 2 4 5]Осторожно: это изменяет backing array. Если где-то есть другой слайс, ссылающийся на тот же массив — он увидит изменения.
Двумерные слайсы
// Матрица 3x3
matrix := make([][]int, 3)
for i := range matrix {
matrix[i] = make([]int, 3)
}
matrix[1][1] = 5Ёмкость и производительность
Если знаешь финальный размер — передай cap в make:
// Плохо: много реаллокаций
result := []int{}
for i := 0; i < 10000; i++ {
result = append(result, i*i)
}
// Хорошо: один раз выделяем нужную память
result := make([]int, 0, 10000)
for i := 0; i < 10000; i++ {
result = append(result, i*i)
}Разница в производительности может быть в 5–10 раз на больших слайсах.