Ответ
Ключевое различие в том, что массив имеет фиксированный размер, определенный на этапе компиляции, а срез — это динамическая, гибкая обертка над массивом.
Массив (Array)
- Фиксированный размер: Размер массива является частью его типа. Например,
[3]int
и[4]int
— это два разных, несовместимых типа. - Изменить размер нельзя: После создания массива его длину изменить невозможно. Попытка доступа к элементу за пределами его длины приведет к ошибке компиляции или панике во время выполнения.
- Тип-значение (Value Type): При присваивании или передаче в функцию массив копируется целиком.
// Размер 3 является частью типа
var arr [3]int
arr[0] = 1
// arr[3] = 4 // Ошибка компиляции: invalid array index 3 (out of bounds for 3-element array)
Срез (Slice)
- Динамический размер: Срез можно расширять с помощью встроенной функции
append
. - Обертка над массивом: Срез не хранит данные напрямую. Он представляет собой структуру с тремя полями: указатель на базовый массив, длина (length) и ёмкость (capacity).
- Ссылочное поведение (Reference Type): При присваивании или передаче в функцию копируется сама структура среза, но указатель продолжает ссылаться на тот же базовый массив. Изменение элементов в одном срезе будет видно в другом, если они ссылаются на один массив.
// Изначально срез пустой
var slice []int
// Добавляем элементы, Go управляет размером базового массива под капотом
slice = append(slice, 1) // slice теперь [1]
slice = append(slice, 2, 3) // slice теперь [1, 2, 3]
Итог: Для коллекций, размер которых может меняться во время выполнения программы, всегда следует использовать срезы. Массивы применяются редко, в основном когда требуется точный контроль над расположением данных в памяти.