Комментарии 16
У меня только один вопрос - зачем это вообще нужно? Выглядит как добавление лишней сущности.
Можно ли было оставить Go без массивов вообще
Массивы в го - бесплатные. Т.е. на них не тратятся дополнительные ресурсы.
Для слайсов в любом случае пришлось бы выделять кусок памяти и хранить на него указатель. Массив - это и есть просто сырой кусок памяти.
Каждый слайс - это +16 байт. Это может мешать, если у вас очень много мелких сущностей - это конечно случай граничный, но не нереалистичный. Пример - IP адреса, хеши, да и вообще всё у чего не меняется размер. Для IPv4 заголовок слайса занимает большую часть хранилища.
Не совсем очевидный момент, но массивы лучше переживают escape to heap. По крайней мере раньше можно было выделить массив большего размера, прежде чем он вытесняется в кучу.
Хедер слайса: поинтер на массив, длинна и капасити. Поинтер и int (длинна и капасити) - соответствуют разрядности системы.
Для 64 битной архитектуры это 64 + 64 + 64 = 192 бита или 24 байта
Для 32 бит - 12 байт.
Откуда +16 байт у вас взялись - не очень понятно.
поинтер на массив
Откуда +16 байт у вас взялись - не очень понятно
Вы уже подошли очень близко к разгадке.
В слайсе лежит указатель на массив. Если оперировать указателями на массивы (а такое может быть, если вам не хочется их копировать), так или иначе у вас под указатель все равно где-то будут выделяться переменные. А длина (с одной н) и ёмкость - они всегда лишние, если в слайсе/массиве хранятся данные с неизменяемой длиной.
Если вы все равно захотите придраться, что в слайсе на каждый объект хранится указатель, а при работе с массивами - не факт, то я вам отвечу что вы упустили основную деталь. Не важно сколько именно лишних байт, важно то, что они лишние.
В пресловутом случае с IP адресами уже одно поле длины в два раза больше, чем IPv4. Поэтому концептуально нет разницы, во сколько раз слайс больше памяти занимает - в 4 раза, в 6 или в 3 на 32-битной системе.
Вы реально не поняли о чем я.
Массив (как бы вы с ним ни работали) останется массивом и "под" слайсом, но нужны там дина и емкость (пусть будет по грамотному если для вас это так важно) или не нужны, а заголовок слайса все равно будет создан и он займет именно 24/12 байт в зависимости от разрядности системы.
Если считать что переменная это указатель на массив, но в таком случае и переменная типа слайса - это тоже указатель, только на заголовок слайса (а уже тот ссылается на массив).
Т.о. разница между использованием массива и слайса - +24 или +12 байт но не +16.
А по остальным моментам я с вами и не спорил, и повторяться про IP адрес не стоило.
Стоит упомянуть про то, что массивы по семантике ближе к значениям, а слайсы к ссылкам. На практике это заметно в кейсах:
Передача в функцию - массивы копируются
Сравнение - массивы можно сравнивать через оператор ==
for-range - массивы неизменяемы в таком цикле из-за неявного копирования
итак, размер удваивается
Вообще-то удваивается до определенного предела capacity, а дальше в зависимости от размера исходного слайса применяется таблица коэффициентов:
starting cap growth factor
256 2.0
512 1.63
1024 1.44
2048 1.35
4096 1.30
И это начиная с версии 1.18, а до этого просто начиная с capacity 1024 применялся множитель 1.25
Про необходимость массивов.
Если читать какой-нибудь бинарный протокол при помощи binary.Read, то структура с членом-массивом читается без проблем, а если бы это были слайсы - как минимум перед чтением надо было проинициализировать размеры этих слайсов или как-то по-другому передать размеры. Можно, но с массивом гораздо удобнее и ошибкоустойчивее.
функции возвращающие слайсы обычно инициализируют их внутри себя, с этим проблемы особой не видно.
a := []int{3, 1, 4, 1, 5, 9}
maxOfList := max(a...)
Это не работает же.
забавно, похожи на часть моих вопросов, но только на вопрос зачем вообще массивы, который я задаю - у меня есть ответ - работа с ними зачастую более эффективная.
Массивы и слайсы в Go — для собеседований