Go: теги

Структуры один из основных типов данных в Golang. Они используются практически повсеместно (пользовательские типы, конфиги и т.д.). Более того к полям структур через теги могут быть добавлены метаданные, которые нужны для маппинга данных через encoding/json или encoding/xml, валидации, ORM и др.

Рассмотрим использование метаданных на примере маппинга структуры в JSON и обратно. Пусть у нас есть структура, описанная следующим образом:

type User struct {
  Id        int       `json:"id"`
  Name      string    `json:"name"`
  Bio       string    `json:"about,omitempty"`
  Active    bool      `json:"active"`
  Admin     bool      `json:"-"`
  CreatedAt time.Time `json:"created_at"`
}

В случая отсутствия тегов json.Marshal вернул бы JSON следующего вида:

{
  "Id": 1,
  "Name": "John Doe",
  "Bio": "Some Text",
  "Active": true,
  "Admin": false,
  "CreatedAt": "2016-07-16T15:32:17.957714799Z"
}


В случая же с тегами мы имеем следующий результат:​​

{
  "id": 1,
  "name": "John Doe",
  "about": "Some Text",
  "active": true,
  "created_at": "2016-07-16T15:32:17.957714799Z"
}

Использование метаданных позволяет при маппинге выполнить переименование полей, убрать ненужные при помощи `json:"-"` . За более детальной информацией можно обратиться к описанию пакетов JSON и XML .

Чтобы понять как работают теги внутри давайте попробуем создать свой набор метаданных и извлечь их. Для этого нам понадобиться пакет reflect. Давайте рассмотрим, как это работает:

package main

import (
  "fmt"
  "reflect"
)

const tagName = "validate"

type User struct {
  Id    int    `validate:"-"`
  Name  string `validate:"presence,min=2,max=32"`
  Email string `validate:"email,required"`
}

func main() {
  user := User{
    Id:    1,
    Name:  "John Doe",
    Email: "john@example",
  }

  t := reflect.TypeOf(user)

  fmt.Println("Type:", t.Name())
  fmt.Println("Kind:", t.Kind())

  for i := 0; i < t.NumField(); i++ {
    field := t.Field(i)
    tag := field.Tag.Get(tagName)
    tname := field.Type.Name()

    fmt.Printf("%d. %v (%v), tag: '%v'\n", i+1, field.Name, tname, tag)
  }
}

В результате выполнения программы мы получим

Type: User
Kind: struct
1. Id (int), tag: '-'
2. Name (string), tag: 'presence,min=2,max=32'
3. Email (string), tag: 'email,required'

Через пакет reflect нам доступна базовая информация о структуре User: тип, вид, список полей и список связанных с ними тегов.

 

03.05.2017









 
архив

подписка