
Структуры один из основных типов данных в 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:"-"
. За более детальной информацией можно обратиться к описанию пакета encoding/json.
Чтобы понять как работают теги внутри, давайте попробуем создать свой набор метаданных и извлечь их. Для этого нам понадобиться пакет 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: тип, вид, список полей и список связанных с ними тегов.