Основы Go
Теория: Срезы
Срезы (slices) — это основной способ работы с коллекциями переменной длины в Go. В отличие от массивов, срезы не фиксируют количество элементов в типе и позволяют изменять длину коллекции. По сути это аналог списков из других языков.
Технически срез — это обёртка над массивом. Он хранит в себе три вещи:
- Указатель на первый элемент.
- Текущую длину (
len()). - Вместимость (
cap()) — максимальное количество элементов, которые можно хранить, не выделяя новый массив.
Объявление среза
Объявление среза аналогично массиву, с одним исключением. Внутри скобок ничего не указывается, так как длина не известна и может меняться.
Значением по умолчанию в таком определении nums будет nil.
Срез можно создать напрямую с помощью литерала. В этом случае указывается тип элементов, а длина выводится из количества значений:
Можно создать пустой срез, добавив в конце {}:
Пустой срез — это не nil, но он ведёт себя как пустая коллекция. Он готов к использованию и не вызывает ошибок при чтении длины, прохождении в цикле и других типичных операциях.
Такая запись (с добавлением {} в конце) полезна, когда нужно объявить срез заранее, но значения будут добавлены позже (например, в цикле или через append).
Создание среза через make
Функция make() используется для создания срезов с заранее заданной длиной и (опционально) вместимостью. Это бывает полезно для предварительного выделения памяти и улучшения производительности.
Если вы знаете, что срез будет расширяться, но хотите избежать лишних перераспределений памяти, можно задать вместимость больше длины:
Это позволяет избежать постоянного выделения новой памяти при каждом append() — важно в циклах или при работе с большими объёмами данных. С другой стороны, подобные оптимизации нужны далеко не всегда и заниматься ими имеет смысл только тогда, когда эта часть кода уже стала узким горлышком.
Добавление элементов
Для добавления элементов к срезу используется встроенная функция append(). Она возвращает новый срез с добавленными элементами:
Если вместимость позволяет, append() просто дописывает значение. Если нет — Go выделяет новый массив с увеличенной вместимостью.
Можно добавить сразу несколько элементов:
Можно объединять срезы:
Это удобно, например, при объединении результатов нескольких запросов или списков.
Доступ к элементам
Срезы поддерживают доступ по индексу. В этом смысле поведение идентично массивам:
Если обратиться по индексу, которого нет в срезе — будет ошибка во время выполнения (runtime panic), а не на этапе компиляции.
Поэтому перед обращением стоит проверять длину через len().
Передача и возврат из функции
Когда срез передаётся в функцию, копируется только небольшой «заголовок» среза: длина, вместимость и указатель на общий подлежащий массив. Сами элементы не копируются. Поэтому если внутри функции менять элементы по индексу (s[i] = ...), изменения видны и снаружи. Это остаётся передачей по значению (копируется заголовок), просто в нём хранится указатель на данные.
Также можно возвращать срез из функции:
Подробнее о нюансах append() при работе внутри функций (и почему иногда изменения «не выходят» наружу) узнаем в одном из следующих уроков.





