Что будет если не инициализировать слайс в Go
Что проверяют
Знаете ли вы, что нулевое значение среза это nil, и что с ним можно работать почти как с пустым. Вопрос отсеивает тех, кто по привычке из других языков боится любого nil и пишет лишние проверки, и тех, кто путает срез с картой.
Как отвечать
Объявленный без инициализации срез равен nil: указатель на массив нулевой, длина и вместимость равны нулю. При этом он полностью рабочий для чтения и для добавления.
var s []int
fmt.Println(s == nil, len(s), cap(s)) // true 0 0
s = append(s, 1) // выделит массив, вернёт новый срез
for _, v := range s { fmt.Println(v) }append на нулевом срезе корректен: функция сама выделяет память под новый массив. len, cap, range и нарезка s[:0] тоже работают. Падает только обращение по индексу, и не потому что срез нулевой, а потому что длина нулевая: это обычный выход за границы.
Важное отличие от карты: в нулевую карту записать нельзя, там будет паника при присваивании. Поэтому карту через make создавать обязательно, а срез почти никогда не требуется.
Разница, о которой стоит сказать самому, видна при сериализации: нулевой срез превращается в null, а созданный через make пустой срез в []. Для внешнего API это разные ответы, и клиенты на этом ломаются.
Где спотыкаются
Говорят, что append на неинициализированном срезе паникует. Нет, это штатный сценарий, и накопление в объявленную переменную вполне идиоматичный приём.
Второе: проверяют пустоту сравнением с nil. Правильная проверка это len(s) == 0: она покрывает и нулевой срез, и пустой срез с уже выделенной вместимостью, которые между собой не равны.
Третье: думают, что нулевой срез, переданный в функцию, наполнится внутри неё. Срез передаётся по значению, append внутри функции меняет локальную копию заголовка, и вызывающая сторона ничего не увидит, если не вернуть результат.