В Go JSON маршалинг стандартно реализован через пакет encoding/json. Сериализовать можно только экспортируемые (с большой буквы) поля структур. Для управления именами и обработкой используют теги struct:
type User struct { ID int `json:"id"` Name string `json:"name,omitempty"` Age int `json:"age,string"` }
omitempty исключает поле при нулевом значении;string сериализует значение как строку, даже если это число.user := User{ID: 1, Name: "Олег"} b, _ := json.Marshal(user) fmt.Println(string(b)) // {"id":1,"name":"Олег","age":"0"}
var u User json.Unmarshal([]byte('{"id":2,"name":"Иван"}'), &u)
Как сериализуются неэкспортируемые (с маленькой буквы) поля структуры при маршалинге в JSON?
Правильный ответ: Они игнорируются, в сериализации участвуют только экспортируемые (с большой буквы) поля. Это часто внезапно ломает API:
type Foo struct { bar int // не будет сериализовано! }
История
Бэкенд выдавал неполные JSON-объекты, т.к. часть нужных полей осталась неэкспортируемой (с маленькой буквы). Несколько дней ушло на выяснение, почему клиенты не видят эти поля.
История
В ответе API поле содержало конструкцию omitempty, но иногда приходило пустое значение, потому что нулевое значение для среза — это nil, а не пустой срез. Клиенты получали null вместо пустого массива [] и падали при парсинге.
История
В проекте подмешивали динамические поля к структурам через map[строка]интерфейс, но забывали реализовать кастомный UnmarshalJSON, из-за чего часть данных "терялась" без ошибок. Данные клиента терялись и вручную восстанавливались по резервным копиям.