Skip to content

JSON Marshal: абстрактные типы данных

В предыдущих примерах мы закодировали значения конкретных типов данных, таких как int, string, bool и т. д. Давай добавим более сложные значения данных, такие как struct, map и interface к объекту, и посмотрим, как он преобразовывается в JSON.

Пришло время поработать с кодом!

В приведенном выше примере мы добавили поле Profile и Languages к структуре Student, имеющей тип Profile и map[string]string соответственно. Эта программа дает следующий результат.

Если вы внимательно посмотрите на этот результат, мы не получили followers поле в Profile объекте, потому что оно не экспортируется из Profile типа.

Структура может иметь анонимно вложенную структуру. В таком случае поля этой структуры (а также методы) продвигаются (forwarding) к родительской структуре.

Подробнее о структурах в Go ты можешь узнать по ссылке.

Пришло время поработать с кодом!

В приведенном выше примере мы сделали Profile поле типа структуры Student анонимным. Это приведет к тому, что все поля Profile будут переведены в тип Student родительской структуры. Это изменение дает следующий результат.

Обрати внимание, что поля Username и Grades теперь являются частью основного объекта. Однако поле Grades закодировано null, потому что оно не было инициализировано, и поскольку нулевое значение в map равно nil, оно было преобразовано в null соответствии с правилом.

Если имя продвигаемого поля конфликтует с именем поля из родительской структуры, то для маршалинга выбирается наименее вложенное поле, то есть поле текущей структуры в приоритете.

Если значение является указателем, то значение указателя используется для маршалинга. Если значением является интерфейс, то для маршалинга используется конкретное значение интерфейса.

Пришло время поработать с кодом!

В приведенном выше примере мы создали тип интерфейса ProfileI, который объявляет метод Follow. Мы реализовали этот метод для типа структуры Profile с аргументом *Profile, что означает, что теперь тип *Profile реализует интерфейс ProfileI.

В структуру Student мы добавили поля Primary и Secondary типа интерфейса ProfileI. ProfileI означает, что этим полям можно присвоить любое значение, реализующее интерфейс.

В функции main мы объявили структуру переменной john типа *Student, назначив указатель типа Student. Мы не присвоили поле Secondary структуре john, но поле Primary содержит указатель на структуру Profile. Это допустимо, потому что поле Primary имеет тип интерфейса ProfileI, а тип *Profile реализует интерфейс ProfileI.

Позже мы вызвали метод john.Primary.Follow() для увеличения счетчика Followers. Если ты заметил, мы передали указатель функции MarshalIndent — это нормальное поведение, потому что функция Marshal использует значение указателя под капотом для преобразования. Эта программа дает следующий результат.

Поле Secondary null из-за значения поля Secondary в структуре john nil (нулевое значение интерфейса nil). Поле Primary является объектом JSON, потому что поле Primary представляет собой интерфейс и имеет указатель на структуру Profile в качестве своего конкретного значения.