Знаком ли с проблемой zero value в Go
Что проверяют
Знаете ли вы нулевые значения разных типов и где они превращаются в панику или тихую ошибку. Следом почти всегда спрашивают про nil-интерфейс, в котором лежит nil-указатель, и про то, как отличить «поле не пришло» от «пришёл ноль».
Как отвечать
Сначала правило: любая переменная в Go инициализирована. Числа получают 0, строки "", bool false, указатели, срезы, мапы, каналы, функции и интерфейсы nil, структуры поэлементно. Хорошие типы проектируют так, чтобы нулевое значение было рабочим: sync.Mutex, bytes.Buffer и strings.Builder можно использовать сразу после var.
Затем сами проблемы:
- nil-мапа: чтение возвращает нулевое значение, а запись вызывает панику. Нужен
makeили литерал; - nil-канал: отправка и чтение блокируются навсегда,
closeвызывает панику; - nil-срез:
appendиlenработают, ноencoding/jsonсериализует его вnull, а пустой срез в[], и клиент может упасть на этой разнице; - неотличимость: после
json.UnmarshalполеAge intравно 0 и когда пришёл ноль, и когда поля не было. Решают указателем*int, для базыsql.Null[T](с Go 1.22) или своим типом-обёрткой; - теги:
omitemptyвыкидывает законные 0 и false, но не выкидывает нулевую структуру вродеtime.Time. С Go 1.24 естьomitzero, который учитывает методIsZero(); - nil в интерфейсе: функция возвращает
error, внутриvar e *MyErr = nil; return e. Интерфейс хранит тип и значение, тип не пустой, поэтомуerr != nilдаёт true.
Отдельно про time.Time{}: это 1 января первого года, проверять его нужно через IsZero().
Где спотыкаются
Проверяют str == "" как признак «не инициализировано». В Go это одно и то же состояние, а пустая строка вполне может быть корректным значением.
Возвращают типизированный nil-указатель как error и потом ищут, почему проверка ошибки срабатывает на успешном пути.
Обвешивают всё указателями ради отличия от нуля. Код обрастает nil-проверками и лишними аллокациями, хотя часто хватает флага или отдельного типа.