omitempty golang что это

JSON с опциональными полями в Go

Перевод статьи подготовлен специально для будущих студентов курса «Golang Developer. Professional».

В частности, наиболее важное различие между опциями и любыми другими данными заключается в том, что опции зачастую, извините за каламбур… опциональны. Наша программа может иметь большое количество всевозможных параметров конфигурации (опций), но нам может понадобиться инициировать какую-либо конкретную инвокацию только с ограниченным их подмножеством, оставив для всего остального значения по умолчанию.

Начнем с основ. Рассмотрим следующую структуру, которая представляет из себя опции произвольной программы:

Эта структура содержит всего 4 опции, но в реальных программах их могут быть десятки.

Предположим, мы хотим указать эти опции в JSON-файле конфигурации. Полный список опций может выглядеть примерно так:

На практике же достаточно редко все бывает так просто. Нам следует обработать сразу несколько особых случаев:

В JSON-конфиге могут отсутствовать некоторые поля, и мы хотим, чтобы наша структура в Go имела для них значения по умолчанию.

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

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

Теперь парсинг вышеупомянутого фрагмента JSON приведет к ошибке.

Потому что все остальные поля имеют нулевые значения. Если вы напротив хотите всегда вносить все поля, не указывайте omitempty.

Установка значений по умолчанию

В приведенном выше примере мы видели, что отсутствующие в JSON-представлении поля будут преобразованы в нулевые значения Go. Это нормально, если значения ваших параметров по умолчанию также являются их нулевыми значениями, что не всегда так. Что, если значение по умолчанию Power должно быть 10, а не 0? То есть, когда JSON не имеет поля «power», вы хотите установить Power равным 10, но вместо этого Unmarshal устанавливает его в ноль.

На самом деле, эта проблема решается наоборот. Мы установим значения по умолчанию сначала, а затем позволим json.Unmarshal перезаписать поля по мере необходимости:

В качестве альтернативы мы можем хитро спрятать эту логику в пользовательском методе UnmarshalJSON для Options :

Этот подход прост и понятен, но у него есть некоторые недостатки. Во-первых, он прочно связывает значения полей по умолчанию с логикой парсинга. Вполне возможно, что мы хотим, чтобы пользовательский код устанавливал значения по умолчанию позже; прямо сейчас значения по умолчанию нужно установить перед анмаршалингом.

Второй недостаток заключается в том, что это работает только для простых случаев. Если наша структура Options содержит срез или мапу других структур, мы не сможем проставить значения по умолчанию таким образом. Примите во внимание:

Альтернативой является использование совершенно другого подхода, перекладывая логику значений по умолчанию на пользователя. Мы можем добиться этого с помощью полей-указателей.

Значения по умолчанию и поля-указатели

Мы можем определить нашу структуру Options как:

Это очень напоминает исходное определение, за исключением того, что все поля теперь являются указателями. Предположим, у нас есть следующий текст JSON:

Обратите внимание, что указаны все поля, кроме «power». Мы можем анмаршалить это как обычно:

Но теперь мы можем четко различить поля, которые не были указаны вообще (они будут анмаршалены в nil указатель), и поля, которые были указаны с нулевыми значениями (они будут анмаршалены в валидные указатели на значения с нулевыми значениями). Например, мы можем написать следующую обертку парсера для анмаршалинга Options и установки значений по умолчанию по мере необходимости:\

Источник

Структурные теги в Go

Структуры в Go используются для сбора нескольких фрагментов информации в один блок. Эти коллекции информации используются для описания понятий более высокого уровня: так же, как адрес состоит из улицы, города, области и почтового индекса. При чтении этой информации из таких систем, как базы данных или API, вы можете использовать теги. Теги управляют назначением этой информации и присваивают ее полям структуры. Структурные теги – это небольшие фрагменты метаданных, закрепленные за полями структуры; теги содержат инструкции для другого кода Go, который работает с данной структурой.

Как выглядит структурный тег?

Структурные теги Go представляют собой аннотации, которые появляются в объявлении структуры Go после типа. Каждый тег состоит из коротких строк, связанных с некоторым соответствующим значением.

Структурный тег выглядит следующим образом:

type User struct <
Name string `example:»name»`
>

Другой код Go может затем проверить эти структуры и извлечь значения, присвоенные определенным ключам, которые он запрашивает. Структурные теги не влияют на работу вашего кода, если у вас нет какого-либо другого кода, который их проверяет.

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

package main
import «fmt»
type User struct <
Name string `example:»name»`
>
func (u *User) String() string <
return fmt.Sprintf(«Hi! My name is %s», u.Name)
>
func main() <
u := &User <
Name: «Sammy»,
>
fmt.Println(u)
>

Hi! My name is Sammy

В этом примере определяется тип User с полем Name. Поле Name было присвоено структурному тегу example:”name”. Структурный тег example имеет значение “name” для поля Name. Для типа User мы определяем метод String(), требуемый интерфейсом fmt.Stringer. Он вызовется автоматически, когда мы передадим тип в fmt.Println, что даст возможность создать красиво отформатированную версию нашей структуры.

В теле main мы создаем новый экземпляр типа User и передаем его в fmt.Println. В структуре присутствовал тег struct, но он не влияет на работу этого кода Go. Код будет вести себя точно так же, даже если структурного тега в не мне будет.

Чтобы использовать структурные теги для выполнения каких-то операций, необходимо написать другой код Go для проверки структур. Стандартная библиотека предоставляет пакеты, которые используют структурные теги в своей работе. Наиболее популярным из них является пакет encoding/json.

Пакет encoding/json

JavaScript Object Notation (JSON) – это текстовый формат для кодирования наборов данных, организованных под разными строковыми ключами. Обычно этот формат используется для обмена данными между различными программами, поскольку он достаточно прост, а потому существует много библиотек для его декодирования на разных языках. Вот пример JSON:

Этот объект JSON содержит два ключа, language и mascot. После этих ключей идут соответствующие значения. Здесь ключ language имеет значение Go, а mascot присваивается значение Gopher.

Энкодер JSON в стандартной библиотеке использует структурные теги в качестве аннотаций, которые указывают, как вы хотели бы назвать свои поля в выводе JSON. Эти механизмы кодирования и декодирования JSON можно найти в пакете encoding/json.

Попробуйте выполнить этот пример, чтобы увидеть, как JSON выполняет кодирование без тегов структуры:

Вы получите такой вывод:

<
«Name»: «Sammy the Shark»,
«Password»: «fisharegreat»,
«CreatedAt»: «2019-09-23T15:50:01.203059-04:00»
>

Мы определили структуру, описывающую пользователя, в качестве полей она включает имя, пароль и время создания пользователя. В рамках функции main мы создаем экземпляр этого пользователя, предоставляя значения для всех полей, кроме PreferredFish. Затем мы передаем экземпляр User в функцию json.MarshalIndent. Это позволяет просмотреть вывод JSON без использования внешнего инструмента форматирования. Этот вызов можно заменить на json.Marshal(u), чтобы получить JSON без дополнительных пробелов. Два дополнительных аргумента json.MarshalIndent управляют префиксом вывода (мы опускаем его) и символами отступа (здесь это два пробела). Все ошибки, вызванные json.MarshalIndent, логируются, и программа Затем мы, мы преобразуем []byte (возвращенный из json.MarshalIndent) в строку и передаем полученную строку в fmt.Println для вывода в терминал.

Поля структуры отображаются точно так, как мы их назвали. Это не типичный стиль JSON, который использует верблюжий регистр для полей. В следующем примере мы попробуем изменить имена полей в соответствии со стандартным стилем JSON. Как вы увидите позже, это не сработает, поскольку целевые имена полей конфликтуют с правилами Go об именовании экспортированных полей.

Вы получите такой вывод:

В этом примере мы отредактировали имена полей, чтобы они были записаны в верблюжьем регистре: теперь поле Name записано как name, Password – как password, а CreatedAt – как createdAt. В теле main мы изменили экземпляр структуры, чтобы использовать эти новые имена. Затем мы передаем структуру в функцию json.MarshalIndent. В результате мы получили пустой объект JSON, <>.

Верблюжий регистр в именах полей подразумевает, что имя начинается с нижнего регистра. В целом JSON не следит за тем, как вы называете свои поля, но для Go это имеет значение, поскольку это указывает на видимость поля вне пакета. Поскольку пакет encoding/json является отдельным пакетом вне пакета main, который мы используем, мы должны записать имена с заглавной буквы, чтобы сделать поля доступными для пакета encoding/json. Казалось бы, это тупик. Нам нужно придумать, как передать кодеру JSON требуемый формат имен этих полей.

Использование структурных тегов для управления кодировкой

Вы можете изменить предыдущий код, чтобы экспортируемые поля были правильно закодированы, а их имена записаны в верблюжьем регистре. Здесь нам пригодятся структурные теги, с помощью которых мы отметим каждое поле. Структурный тег, который распознает encoding/json, имеет ключ json и значение, управляющее выводом. Поместив имена полей в верблюжьем регистре в качестве значения ключа json, вы сообщите кодеру, что такие имена нужно использовать. Вот как выглядит код:

Вывод получится такой:

<
«name»: «Sammy the Shark»,
«password»: «fisharegreat»,
«preferredFish»: null,
«createdAt»: «2019-09-23T18:16:17.57739-04:00»
>

Мы вернули имена полей, чтобы они были видны другим пакетам – теперь они снова начинаются с заглавных букв. Однако на этот раз мы добавили структурные теги json:”name”, где :”name” – это имя, которое должно использоваться в json.MarshalIndent при выводе структуры как JSON.

Итак, мы успешно отформатировали JSON. Однако обратите внимание, что в выводе есть поля для пустых значений (мы не устанавливали эти значения). Энкодер JSON может удалить такие поля.

Удаление пустых полей JSON

Чаще всего вывод полей с пустыми значениями подавляется. Поскольку все типы в Go имеют нулевое значение, то есть какое-то значение по умолчанию, которое им задано, пакету encoding/json требуется дополнительная информация, чтобы понять, какое поле следует считать неустановленным, если оно принимает это нулевое значение. В пределах значения любого структурного тега с помощью параметра omitempty вы можете добавить суффикс к желаемому имени поля, чтобы сообщить кодеру JSON, что вывод этого поля нужно подавить, если оно имеет нулевое значение. Следующий код больше не будет выводить пустые поля:

<
«name»: «Sammy the Shark»,
«password»: «fisharegreat»,
«createdAt»: «2019-09-23T18:21:53.863846-04:00»
>

Мы изменили предыдущий код так, чтобы поле PreferredFish теперь имело структурный тег json:”preferredFish,omitempty”. Наличие суффикса omitempty заставляет кодер JSON пропустить это поле, поскольку мы решили оставить его значение пустым. Оно имело значение null в выходных данных предыдущих запусков кода.

Сейчас вывод выглядит намного лучше, но в нем до сих пор есть пароль пользователя. Пакет encoding/json позволяет нам полностью игнорировать частные поля.

Игнорирование частных полей

Некоторые поля должны быть экспортированы из структур, чтобы другие пакеты могли правильно взаимодействовать с типом. Однако некоторые поля могут содержать конфиденциальную информацию, поэтому в этих обстоятельствах энкодер JSON должен игнорировать их, даже если значение установлено. Это делается с помощью специального значения – оно применяется в качестве аргумента значения тега json: struct.

Вот так выглядит код, который будет скрывать пароль пользователя.

Запустив его, вы получите такой результат:

<
«name»: «Sammy the Shark»,
«createdAt»: «2019-09-23T16:08:21.124481-04:00»
>

Единственное, что мы изменили в этом примере по сравнению с предыдущими – мы внесли специальное значение “-” в поле пароля для тега json: struct. Мы видим, что в выходных данных поле пароля больше не отображается.

Функции пакета encoding/json, omitempty и значение “-” не являются стандартами. Что пакет решит сделать со значениями структурного тега, зависит от его реализации. Поскольку пакет encoding/json является частью стандартной библиотеки, другие пакеты также реализовали эти функции по соглашению. Важно читать документацию всех сторонних пакетов, которые используют структурные теги, чтобы узнать, что поддерживается пакетами, а что нет.

Заключение

Структурные теги предлагают мощные средства для расширения функциональности кода, который работает с вашими структурами. Многие стандартные библиотеки и сторонние пакеты позволяют настроить их работу с помощью этих тегов. Эффективное использование тегов в вашем коде обеспечивает необходимое поведение и лаконично документирует, как эти поля используются в программе.

Источник

JSON с опциональными полями в Go

Перевод статьи подготовлен специально для будущих студентов курса «Golang Developer. Professional».

В частности, наиболее важное различие между опциями и любыми другими данными заключается в том, что опции зачастую, извините за каламбур… опциональны. Наша программа может иметь большое количество всевозможных параметров конфигурации (опций), но нам может понадобиться инициировать какую-либо конкретную инвокацию только с ограниченным их подмножеством, оставив для всего остального значения по умолчанию.

Начнем с основ. Рассмотрим следующую структуру, которая представляет из себя опции произвольной программы:

Эта структура содержит всего 4 опции, но в реальных программах их могут быть десятки.

Предположим, мы хотим указать эти опции в JSON-файле конфигурации. Полный список опций может выглядеть примерно так:

На практике же достаточно редко все бывает так просто. Нам следует обработать сразу несколько особых случаев:

В JSON-конфиге могут отсутствовать некоторые поля, и мы хотим, чтобы наша структура в Go имела для них значения по умолчанию.

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

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

Теперь парсинг вышеупомянутого фрагмента JSON приведет к ошибке.

Потому что все остальные поля имеют нулевые значения. Если вы напротив хотите всегда вносить все поля, не указывайте omitempty.

Установка значений по умолчанию

В приведенном выше примере мы видели, что отсутствующие в JSON-представлении поля будут преобразованы в нулевые значения Go. Это нормально, если значения ваших параметров по умолчанию также являются их нулевыми значениями, что не всегда так. Что, если значение по умолчанию Power должно быть 10, а не 0? То есть, когда JSON не имеет поля «power», вы хотите установить Power равным 10, но вместо этого Unmarshal устанавливает его в ноль.

На самом деле, эта проблема решается наоборот. Мы установим значения по умолчанию сначала, а затем позволим json.Unmarshal перезаписать поля по мере необходимости:

В качестве альтернативы мы можем хитро спрятать эту логику в пользовательском методе UnmarshalJSON для Options :

Этот подход прост и понятен, но у него есть некоторые недостатки. Во-первых, он прочно связывает значения полей по умолчанию с логикой парсинга. Вполне возможно, что мы хотим, чтобы пользовательский код устанавливал значения по умолчанию позже; прямо сейчас значения по умолчанию нужно установить перед анмаршалингом.

Второй недостаток заключается в том, что это работает только для простых случаев. Если наша структура Options содержит срез или мапу других структур, мы не сможем проставить значения по умолчанию таким образом. Примите во внимание:

Альтернативой является использование совершенно другого подхода, перекладывая логику значений по умолчанию на пользователя. Мы можем добиться этого с помощью полей-указателей.

Значения по умолчанию и поля-указатели

Мы можем определить нашу структуру Options как:

Это очень напоминает исходное определение, за исключением того, что все поля теперь являются указателями. Предположим, у нас есть следующий текст JSON:

Обратите внимание, что указаны все поля, кроме «power». Мы можем анмаршалить это как обычно:

Но теперь мы можем четко различить поля, которые не были указаны вообще (они будут анмаршалены в nil указатель), и поля, которые были указаны с нулевыми значениями (они будут анмаршалены в валидные указатели на значения с нулевыми значениями). Например, мы можем написать следующую обертку парсера для анмаршалинга Options и установки значений по умолчанию по мере необходимости:\

Источник

Использование тегов структур в Go

Published on January 24, 2020

Введение

Как выглядит структурный тег?

Структурные теги в Go представляют собой аннотации, которые отображаются после типа в декларации структуры Go. Каждый тег состоит из коротких строк, которым назначены определенные значения.

Структурный тег выделяется символами апострофа “”` и выглядит следующим образом:

Другой код Go может оценивать структуры и извлекать значения, назначенные определенным ключам, которые он запрашивает. Структурные теги не влияют на работу кода без кода, который их использует.

С помощью этого примера вы увидите, как выглядят структурные теги, и как они не действуют без кода из другого пакета.

Результат будет выглядеть так:

Кодировка JSON

JavaScript Object Notation (JSON) представляет собой текстовый формат кодирования наборов данных, организованных по различным ключам строк. Он обычно используется для обмена данными между разными программами, поскольку имеет достаточно простой формат для расшифровки библиотеками многих разных языков. Ниже приведен пример JSON:

В этом примере показана кодировка JSON без структурных тегов:

Этот код распечатывает следующее:

Поля структуры соответствуют присвоенным им именам. Это не обычный стиль JSON, где используются названия полей, где первая буква каждого слова, кроме первого, — заглавная («верблюжий стиль»). Вы можете изменить имена полей в соответствии с «верблюжьим стилем», как показано в следующем примере. Как видно при выполнении этого образца, это не сработает, поскольку желаемые имена полей противоречат правилам Go в отношении имен экспортируемых полей.

В результате выводится следующее:

Использование структурных тегов для управления кодировкой

Результат будет выглядеть так:

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

Удаление пустых полей JSON

Результат выполнения будет выглядеть так:

Теперь результаты выглядят намного лучше, однако мы по прежнему распечатываем пароль пользователя. Пакет encoding/json дает нам еще один способ полностью игнорировать конфиденциальные поля.

Игнорирование конфиденциальных полей

В этом примере мы исправили проблему раскрытия пароля пользователя.

При запуске этого примера вы увидите следующие результаты:

Заключение

Структурные теги дают мощные возможности улучшения функциональности кода, работающего с вашими структурами. Многие стандартные библиотеки и сторонние пакеты поддерживают индивидуальные настройки с помощью структурных тегов. Их эффективное использование в коде поддерживает персонализацию поведения, а также в них кратко документируется использование этих полей будущими разработчиками.

Источник

Пустые или необязательные поля структуры в golang

Я новичок в типизированных языках, таких как Go, и пытаюсь изучить лучшие способы реализации.

У меня есть две структуры, представляющие модели, которые будут вставлены в базу данных mongodb. Одна структура (Инвестиции) имеет другую структуру (Группа) как одно из полей.

Проблема, с которой я столкнулся, заключается в том, что в инвестиционной модели группа не требуется. Если группы нет, думаю, ее лучше в БД не вставлять. Как лучше всего работать с такой моделью БД в Go?

2 ответа

bson по умолчанию использует имя поля в нижнем регистре, поэтому вы можете опустить его из тега структуры, когда они совпадают. json по умолчанию будет использовать имя с заглавной буквы, поэтому укажите имя в нижнем регистре в теге, если вам нужны строчные буквы.

Итак, в лучшем случае, возможно, вы можете просто использовать:

Поле структуры может быть примитивного типа (string, int, bool и т. Д.) Или даже другого типа структуры.

Поэтому иногда мы не хотим, чтобы поле структуры входило в данные json (может быть вставлено в базу данных или во внешнем вызове API), если они пусты.

Пример :

Если мы хотим, чтобы Символ и Группа содержали пустые значения (0, false, нулевой указатель, интерфейс / структура нулевого размера), мы можем избежать их при маршалинге json, как показано ниже.

И, очевидно, мы будем заполнять значения в поле Group, как показано ниже.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *