Ответ
Массив и срез — это базовые структуры для работы с последовательностями данных в Go, но они имеют фундаментальные различия.
Массив (Array)
- Фиксированный размер: Размер массива определяется на этапе компиляции и является частью его типа. Например,
[3]int
и[5]int
— это два совершенно разных, несовместимых типа. - Передача по значению: При передаче в функцию массив всегда копируется целиком. Это может быть неэффективно для больших массивов.
- Хранение: Часто размещается на стеке, если размер позволяет, что обеспечивает быстрый доступ.
Срез (Slice)
- Динамический размер: Срез — это легковесная обертка над массивом, размер которой может меняться во время выполнения с помощью функции
append
. - Внутренняя структура: Срез представляет собой заголовок (header), который содержит три поля:
Указатель
на первый элемент базового массива.Длина (len)
— количество элементов в срезе.Ёмкость (cap)
— количество элементов в базовом массиве от указателя до конца массива.
- Передача по ссылке (по поведению): В функцию передается копия заголовка среза. Так как заголовок содержит указатель на тот же базовый массив, изменения элементов среза внутри функции будут видны снаружи. Однако, если
append
вызовет переаллокацию (создание нового массива), связь с оригинальным срезом будет потеряна, поэтомуappend
всегда нужно использовать с присваиванием:slice = append(slice, ...)
.
Сводная таблица отличий:
Характеристика | Массив ([N]T ) | Срез ([]T ) |
---|---|---|
Размер | Фиксированный, часть типа | Динамический, может меняться |
Передача в функцию | По значению (полное копирование) | По значению (копируется заголовок), ведет себя как по ссылке |
Гибкость | Низкая | Высокая (операции append , copy , срезы) |
Нулевое значение | Массив, заполненный нулевыми значениями типа | nil (указатель nil , len=0 , cap=0 ) |
Пример:
// Массив (фиксированный размер, тип [3]int)
arr := [3]int{1, 2, 3}
// Срез (динамический размер, тип []int)
slice := []int{1, 2, 3}
slice = append(slice, 4) // Размер изменился
// Срез, созданный из массива
sliceFromArr := arr[1:3] // len=2, cap=2
Вывод: В 99% случаев в Go для работы с коллекциями следует использовать срезы из-за их гибкости и удобства.