Ответ
Прямого аналога с названием «динамический массив» в Go нет. Эту роль выполняют срезы (slices), которые являются гибкой и мощной абстракцией над обычными массивами.
Как срез работает под капотом?
Срез — это легковесная структура (заголовок среза), содержащая три поля:
- Указатель (pointer): Адрес первого элемента в базовом (скрытом) массиве.
- Длина (length,
len
): Количество элементов в срезе. - Ёмкость (capacity,
cap
): Количество элементов в базовом массиве, начиная от указателя среза.
Именно связка len
и cap
обеспечивает "динамическое" поведение.
Динамический рост с помощью append
Когда вы добавляете элементы с помощью append
:
- Если
len < cap
: В базовом массиве еще есть место. Новый элемент просто записывается в следующую ячейку, иlen
среза увеличивается. - Если
len == cap
: Места нет. Go выделяет новый, больший массив, копирует в него все старые данные, добавляет новый элемент, и указатель в срезе обновляется, чтобы указывать на этот новый массив. Ёмкость (cap
) также увеличивается (обычно удваивается для небольших срезов).
Примеры операций:
// Создание среза. len=3, cap=3
nums := []int{1, 2, 3}
// Добавление элемента. Происходит реаллокация.
// Новый базовый массив будет иметь cap, например, 6
nums = append(nums, 4) // [1, 2, 3, 4]
// Удаление элемента (например, по индексу 1)
// Реаллокации нет, используется тот же базовый массив
nums = append(nums[:1], nums[2:]...) // [1, 3, 4]
Ключевое отличие от массива (array)
- Массив:
[5]int
— его длина5
является частью типа. Размер фиксирован. - Срез:
[]int
— его длина не является частью типа. Размер может меняться.