Парсинг json в golang

Для парсинга cуществует стандартный модуль json и конкретно ф-ция Unmarshal.
func Unmarshal(data []byte, v interface{}) error


Парсинг производится в заранее подготовленную переменную v.
В случае парсинга в структуру, интересующие поля структуры должны быть публичными, (называться с заглавной буквы) иначе json не сможет изменить их и они будут сохранять дефолтные значения.

Интересна ситуация, когда надо распарсить структуру с числовыми полями, эти поля могут быть опциональны. В этом случае поля структуры сохранят свои дефолтные значения, т.е. 0.

var s struct{ Id int }
// Парсим пустой json в структуру с числовым полем
json.Unmarshal([]byte(`{}`), &s)

// Выведет 0, на самом деле, как мы видели, 0 не передавался
log.PrintLn(s.Id)


Как отличить ситуацию, когда поля вовсе не было от ситуации с реально переданным нулём?
Как один из вариантов может быть парсинг в указатель, т.к. в случае отсутствия ключа, поле структуры-указатель примет значение nil, а при переданном ключе там будет указатель на число.

var s struct{ Id *int }
// Парсим пустой json в структуру с числовым полем
json.Unmarshal([]byte(`{}`), &s)

if s.Id == nil {
   // Ничего не передавалось
}


Для ускорения массовой генерации json для структур можно использовать модуль ffjson, повторяющий интерфейс модуля json.
ffjson на этапе компиляции генерирует код парсинга каждой структуры и использует этот код в реалтайме, обходясь без более долгоработающего модуля reflect. Плюсы модуля — в 2-3 раза более быстрая генерация. Минусы — больший бинарник.