Массивы: длина — часть типа
Сергей выдал Мише первую задачу — импорт каталога для «Полки». Миша завёл под запись массив из пяти полей.
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
К вечеру функция, написанная под пять полей, отказалась принимать шесть — хорошо, что компилятор ее не собрал и проблем в проде удалось избежать.
Массив — это N значений одного типа, и N входит в тип на этапе компиляции: [3]int и [4]int — разные типы; массив копируется целиком (по семантике), а место массивов в реальном коде — буферы.
Почему так произошло?
Если рассматривать массив с точки зрения памяти, то его длина будет являться частью типа, которая устанавливается при компиляции приложения.
Таким образом [3]int и [4]int будут двумя разными типами, как int и string.
Нельзя объявить параметр вида [N]int, который работал бы с длиной M — для каждой длины свой тип.
Так как длина — часть типа, то компилятору не нужно смотреть на данные: размер массива считается как длина × размер элемента.
Выберите тип элемента T — карточки пересчитаются, а ниже появится пояснение про байты.
Массив — это значение, а не ссылка на данные
При присваивании или передаче в функцию копируется весь массив, со всеми элементами.
Запустите код ниже в пошаговом режиме и посмотрите как изменяется память на каждом шаге выполнения программы.
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
Каждый вызов copyArray получает собственную копию массива. В этом примере мы сохраняем адрес каждой копии, поэтому она остаётся в куче — на диаграмме видно, как память растёт примерно на 1 МБ за вызов.
Для больших массивов такое копирование может быть дорогим, поэтому их часто передают по указателю или используют слайсы.
Сравнение
Массивы сравниваются через == поэлементно, если их элементы сравнимы. Это отличает их от слайсов, которые сравнивать нельзя.
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
Где массивы живут в реальном коде
Массивы используют там, где размер является частью данных: фиксированные буферы, хеши, идентификаторы. Для динамических коллекций есть слайс.
Вы узнаете:
- что такое
arr[:]и как это связано со слайсом - как
[...]int{1,2,3}сам считает длину
Проверьте себя
Импорт каталога: Миша объявил хранилище [3]int, а сервис вернул пачку по четыре поля. Что произойдёт при var a [3]int; var b [4]int; a = b?
«Полка» сверяет дубликаты каталога через ==. Массивы a := [2]int{1, 2} и b := [2]int{2, 1}. a == b?
правильных ответов
Длина массива — это часть типа, по семантике языка массив копируется целиком.
Массивы можно сравнивать через ==. В прикладном коде — массив часто является буфером фиксированного размера.
10 000 ₽ · 60 минут · онлайн