Jakie są zastosowania tagów w Go?

W Go Language Specification , wymienia krótki przegląd tagów:

Deklaracja pola może być poprzedzona opcjonalnym znacznikiem string literal, który staje się atrybutem dla wszystkich pól w odpowiednim deklaracja polowa. Znaczniki są widoczne poprzez odbicie interfejs, ale w przeciwnym razie są ignorowane.

// 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"
}

To jest bardzo krótkie wyjaśnienie IMO, I zastanawiałem się, czy ktoś mógłby mi podać, jaki byłby pożytek z tych tagów być?

Author: icza, 2012-06-02

2 answers

Znacznik pola umożliwia dołączenie meta-informacji do pola, które można uzyskać za pomocą odbicia. Zwykle jest on używany do dostarczania informacji o transformacji, jak Pole struct jest zakodowane lub dekodowane z innego formatu (lub przechowywane/pobierane z bazy danych), ale można go użyć do przechowywania dowolnych meta-informacji, które chcesz, albo przeznaczone dla innego pakietu lub do własnego użytku.

Jak wspomniano w dokumentacji reflect.StructTag, zgodnie z konwencją wartość łańcucha znacznika jest rozdzieloną spacjami listą par key:"value", na przykład:

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

key zazwyczaj oznacza pakiet, dla którego przeznaczone jest kolejne "value", na przykład json klucze są przetwarzane/używane przez encoding/json paczka.

Jeśli w "value" ma być przekazywana wiele informacji, zwykle określa się je oddzielając przecinkiem (','), np.

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

Zwykle wartość dash ('-') dla "value" oznacza wykluczenie pola z procesu (np. w przypadku json oznacza nie do marszałka ani nie do rozbrojenia tego pola).

Przykład dostępu do niestandardowych tagów za pomocą refleksji

Możemy użyć odbicia (reflect pakiet), aby uzyskać dostęp do wartości znaczników pól struct. Zasadniczo musimy nabyć Type naszej struktury, a następnie możemy odpytywać pola np. za pomocą Type.Field(i int) lub Type.FieldByName(name string). Metody te zwracają wartość StructField która opisuje / reprezentuje pole struct, a {[20] } jest wartością typu StructTag które opisuje / reprezentuje wartość znacznika.

Poprzednio mówiliśmy o "konwencji" . Konwencja ta oznacza, że jeśli jej przestrzegasz, możesz użyć StructTag.Get(key string) metoda, która przetwarza wartość znacznika i zwraca {[7] } z key, którą podałeś. Metoda jest zaimplementowana / wbudowana w tę metodę Get(). Jeśli nie zastosujesz się do konwencji, Get() nie będzie w stanie parsować key:"value" i znaleźć tego, czego szukasz. To też nie problem, ale wtedy musisz zaimplementować własną logikę parsowania.

Jest też StructTag.Lookup() (został dodany w Go 1.7), który jest "podobnie jak Get(), ale odróżnia znacznik nie zawierający podanego klucza od znacznika powiązanego z pustym łańcuchem z podanym kluczem" .

Spójrzmy więc na prosty przykład:

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"))
}

Output (try it on the 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"

[[63]}GopherCon 2015 miał prezentację na temat znaczników struct o nazwie:

The Many Twarze znaczników Struct (slajd) (i wideo )

Oto lista najczęściej używanych kluczy tagów:

 413
Author: icza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-31 17:32:15

Oto bardzo prosty przykład tagów używanych z encoding/json Pakiet kontrolujący interpretację pól podczas kodowania i dekodowania:

Spróbuj na żywo: 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"}

Pakiet json może spojrzeć na Tagi dla pola i dowiedzieć się, jak mapować pole struktury JSON, a także dodatkowe opcje, takie jak czy powinien ignorować puste pola podczas serializacji z powrotem do json.

W zasadzie każdy pakiet może użyć refleksji na pola, aby spojrzeć na wartości znaczników i działać na tych wartościach. Więcej informacji na ich temat znajduje się w pakiecie reflect
http://golang.org/pkg/reflect/#StructTag :

Zgodnie z konwencją, łańcuchy znaczników są konkatenacją opcjonalnie oddzielony spacjami klucz: pary "wartość". Każdy klucz jest niepustym ciągiem znaków składający się ze znaków niekontrolowanych innych niż spacja (U + 0020 " "), quote (U + 0022'"') i colon (U+003A':'). Każda wartość jest cytowana za pomocą U + 0022 znaki "" i Idź ciąg dosłownej składni.

 139
Author: jdi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-17 08:21:27