Массивы и срезы
Массивы фиксированы, а срезы — гибкие. Разбираем append, len, cap и срезы среза.
Срез (slice) — это «окно» поверх массива: гибкая, растущая последовательность элементов одного типа. На практике используют именно срезы.
Массивы: фиксированный размер
Массив в Go имеет размер прямо в типе: [3]int и [4]int — разные типы. Размер нельзя изменить, поэтому массивы используют редко.
package main
import "fmt"
func main() {
var a [3]int // [0 0 0]
a[0] = 10
b := [3]int{1, 2, 3}
fmt.Println(a, b, len(b))
}Вывод:
[10 0 0] [1 2 3] 3
Срезы: то, чем пользуются всегда
Срез объявляют без размера: []int. Создать можно литералом или функцией make. Элементы добавляют через встроенную append.
package main
import "fmt"
func main() {
nums := []int{1, 2, 3}
nums = append(nums, 4, 5)
fmt.Println(nums, len(nums))
}Вывод:
[1 2 3 4 5] 5
Важно: append может вернуть новый срез (если не хватило места), поэтому результат всегда присваивают обратно: nums = append(nums, ...).
len и cap
У среза две характеристики: len — сколько элементов сейчас, cap — сколько помещается без перевыделения памяти. Когда длина упирается в ёмкость, append выделяет больший массив и копирует данные.
package main
import "fmt"
func main() {
s := make([]int, 0, 4) // len=0, cap=4
fmt.Println(len(s), cap(s))
s = append(s, 1, 2, 3)
fmt.Println(len(s), cap(s))
}Вывод:
0 4 3 4
Срезы среза
Из среза можно вырезать подсрез синтаксисом s[low:high]. Элемент с индексом low входит, high — нет (полуинтервал). Получившийся срез делит ту же память с исходным — изменение элемента видно в обоих.
package main
import "fmt"
func main() {
s := []int{10, 20, 30, 40, 50}
mid := s[1:4] // [20 30 40]
fmt.Println(mid)
mid[0] = 99 // меняем общий массив
fmt.Println(s) // изменение видно в исходном
}Вывод:
[20 30 40] [10 99 30 40 50]
Это частый источник недоразумений: подсрез — не копия. Если нужна независимая копия, используйте copy или append в новый срез.
Итог
- Массив фиксирован (
[3]int), срез ([]int) растёт черезappend. - Результат
appendвсегда присваивайте обратно;len≤cap. - Подсрез
s[a:b]делит память с исходным — это не копия.