В чем ключевое различие между массивами (array) и срезами (slice) в Go? Можно ли изменить размер массива после его создания?

Ответ

Ключевое различие в том, что массив имеет фиксированный размер, определенный на этапе компиляции, а срез — это динамическая, гибкая обертка над массивом.

Массив (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]

Итог: Для коллекций, размер которых может меняться во время выполнения программы, всегда следует использовать срезы. Массивы применяются редко, в основном когда требуется точный контроль над расположением данных в памяти.