Какая польза для тегов в Go?

В Go Language Specification в нем упоминается краткий обзор тегов:

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

// A struct corresponding to the TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers.
struct {
  microsec  uint64 "field 1"
  serverIP6 uint64 "field 2"
  process   string "field 3"
}

Это очень короткое объяснение IMO, и мне было интересно, сможет ли кто-нибудь предоставить мне то, что будет использовать эти теги?

Ответ 1

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

Как упоминалось в документации reflect.StructTag, по соглашению значение строки тега представляет собой разделенные пробелом пары key:"value" например:

type User struct {
    Name string `json:"name" xml:"name"`
}

key обычно обозначает пакет, для которого используется следующий "value", например, json ключи обрабатываются/используются encoding/json.

Если в "value" должна быть передана несколько информации, обычно она определяется путем разделения ее на запятую (','), например

Name string `json:"name,omitempty" xml:"name"`

Обычно значение тире ('-') для "value" означает исключение поля из процесса (например, в случае json это означает, что он не должен маршалировать или отменять это поле).

Пример доступа к вашим пользовательским тэгам с использованием отражения

Мы можем использовать отражение (reflect package) для доступа к значениям тега структурных полей. В принципе нам нужно получить Type нашей структуры, а затем мы можем запросить поля, например. с Type.Field(i int) или Type.FieldByName(name string). Эти методы возвращают значение StructField, которые описывают/представляют поле структуры; и StructField.Tag - это значение типа StructTag, которое описывает/представляет значение тега.

Раньше мы говорили о "конвенции". Это соглашение означает, что если вы выполните его, вы можете использовать метод StructTag.Get(key string), который анализирует значение тега и возвращает "value" из key, который вы указываете. Соглашение реализовано/встроено в этот метод Get(). Если вы не соблюдаете соглашение, Get() не сможет проанализировать пары key:"value" и найти то, что вы ищете. Это также не проблема, но тогда вам нужно реализовать свою собственную логику синтаксического анализа.

Также есть StructTag.Lookup() (был добавлен в Go 1.7), который "как Get(), но различает тег, не содержащий данный ключ из тега, связывающий пустую строку с заданным ключом".

Итак, посмотрим простой пример:

type User struct {
    Name  string `mytag:"MyName"`
    Email string `mytag:"MyEmail"`
}

u := User{"Bob", "[email protected]"}
t := reflect.TypeOf(u)

for _, fieldName := range []string{"Name", "Email"} {
    field, found := t.FieldByName(fieldName)
    if !found {
        continue
    }
    fmt.Printf("\nField: User.%s\n", fieldName)
    fmt.Printf("\tWhole tag value : %q\n", field.Tag)
    fmt.Printf("\tValue of 'mytag': %q\n", field.Tag.Get("mytag"))
}

Выход (попробуйте на Go Playground):

Field: User.Name
    Whole tag value : "mytag:\"MyName\""
    Value of 'mytag': "MyName"

Field: User.Email
    Whole tag value : "mytag:\"MyEmail\""
    Value of 'mytag': "MyEmail"

В GopherCon 2015 появилась презентация о тэгах struct, называемых:

Множество стилей тегов (слайд)видео)

Вот список широко используемых ключей тегов:

Ответ 2

Вот простой пример тегов, которые используются с пакетом encoding/json для управления интерпретацией полей во время кодирования и декодирования:

Попробуйте жить: http://play.golang.org/p/BMeR8p1cKf

package main

import (
    "fmt"
    "encoding/json"
)

type Person struct {
    FirstName  string `json:"first_name"`
    LastName   string `json:"last_name"`
    MiddleName string `json:"middle_name,omitempty"`
}

func main() {
    json_string := `
    {
        "first_name": "John",
        "last_name": "Smith"
    }`

    person := new(Person)
    json.Unmarshal([]byte(json_string), person)
    fmt.Println(person)

    new_json, _ := json.Marshal(person)
    fmt.Printf("%s\n", new_json)
}

// *Output*
// &{John Smith }
// {"first_name":"John","last_name":"Smith"}

Пакет json может посмотреть на теги для поля и рассказать, как сопоставить поле json <= > struct, а также дополнительные параметры, например, следует ли игнорировать пустые поля при сериализации обратно в json.

В принципе, любой пакет может использовать отражение в полях, чтобы посмотреть на значения тегов и действовать на эти значения. В пакете отражения немного больше информации о них
http://golang.org/pkg/reflect/#StructTag:

По соглашению, строки тегов являются конкатенацией опционально ключ, разделенный пробелом: пары "значение". Каждый ключ представляет собой непустую строку состоящий из неконтролируемых символов, кроме пробела (U + 0020 ''), quote (U + 0022 '"') и двоеточие (U + 003A ':'). Каждое значение цитируется с использованием U + 0022 '' 'и синтаксис строкового литерала Go.