Quali sono gli usi per i tag in Go?

Nella specifica della lingua Go , cita una breve panoramica dei tag:

Una dichiarazione di campo può essere seguita da un tag letterale stringa facoltativo, che diventa un attributo per tutti i campi nella dichiarazione di campo corrispondente. I tag sono resi visibili attraverso un’interfaccia di riflessione, ma sono altrimenti ignorati.

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

Questa è una spiegazione molto breve IMO, e mi stavo chiedendo se qualcuno potrebbe darmi quello che uso sarebbero questi tag?

Un tag per un campo consente di albind meta-informazioni al campo che può essere acquisito utilizzando il riflesso. Solitamente viene utilizzato per fornire informazioni di trasformazione su come un campo struct viene codificato o decodificato da un altro formato (o memorizzato / recuperato da un database), ma è ansible utilizzarlo per memorizzare qualunque meta-informazione che si desidera, o destinato ad un altro pacchetto o per uso personale.

Come menzionato nella documentazione di reflect.StructTag , per convenzione il valore di una stringa di tag è un elenco di key:"value" separate da spazi key:"value" coppie key:"value" , ad esempio:

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

La key indica in genere il pacchetto per il "value" successivo, ad esempio le chiavi json vengono elaborate / utilizzate dal pacchetto encoding/json .

Se più informazioni devono essere passate nel "value" , di solito è specificato separandolo con una virgola ( ',' ), ad es.

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

Solitamente un valore tratteggiato ( '-' ) per il "value" significa escludere il campo dal processo (ad es. In caso di json significa non maresciallo o non marziale quel campo).

Esempio di accesso ai tag personalizzati mediante la riflessione

Possiamo usare reflection ( reflect package) per accedere ai valori tag dei campi struct. Fondamentalmente abbiamo bisogno di acquisire il Type della nostra struct, e quindi possiamo interrogare i campi ad es. Con Type.Field(i int) o Type.FieldByName(name string) . Questi metodi restituiscono un valore di StructField che descrive / rappresenta un campo struct; e StructField.Tag è un valore di tipo StructTag che descrive / rappresenta un valore di tag.

In precedenza abbiamo parlato di “convenzione” . Questa convenzione significa che, se la segui, puoi utilizzare il StructTag.Get(key string) che analizza il valore di un tag e ti restituisce il "value" della key specificata. La convenzione è implementata / incorporata in questo metodo Get() . Se non segui la convenzione, Get() non sarà in grado di analizzare la key:"value" coppie key:"value" e trovare ciò che stai cercando. Anche questo non è un problema, ma devi implementare la tua logica di analisi.

Inoltre c’è StructTag.Lookup() (è stato aggiunto in Go 1.7) che è “come Get() ma distingue il tag che non contiene la chiave data dal tag che associa una stringa vuota con la chiave data” .

Quindi vediamo un semplice esempio:

 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 (provalo su 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 ha avuto una presentazione sui tag struct chiamati:

I tag Many Faces of Struct (diapositiva) (e un video )

Ecco un elenco di chiavi tag comunemente usate:

  • json – usato dal pacchetto encoding/json , dettagliato su json.Marshal()
  • xml – usato dal pacchetto encoding/xml , dettagliato su xml.Marshal()
  • bson – usato da gobson , dettagliato su bson.Marshal()
  • protobuf – utilizzato da github.com/golang/protobuf/proto , dettagliato nel pacchetto doc
  • yaml – usato dal pacchetto gopkg.in/yaml.v2 , dettagliato su yaml.Marshal()
  • db : usato dal pacchetto github.com/jmoiron/sqlx ; utilizzato anche dal pacchetto github.com/go-gorp/gorp
  • orm : utilizzato dal pacchetto github.com/astaxie/beego/orm , dettagliato su Models – Beego ORM
  • gorm – usato dal pacchetto github.com/jinzhu/gorm , gli esempi possono essere trovati nel loro documento: Modelli
  • valid – utilizzato dal pacchetto github.com/asaskevich/govalidator , gli esempi possono essere trovati nella pagina del progetto
  • datastore – utilizzato da appengine/datastore (piattaforma Google App Engine, servizio Datastore), dettagliato in Proprietà
  • schema – usato da github.com/gorilla/schema per riempire una struct con valori di modulo HTML, dettagliati nel pacchetto doc
  • asn – usato dal pacchetto encoding/asn1 , dettagliato su asn1.Marshal() e asn1.Unmarshal()
  • csv – usato dal pacchetto github.com/gocarina/gocsv

Ecco un esempio molto semplice di tag usati con il pacchetto encoding/json per controllare come i campi vengono interpretati durante la codifica e la decodifica:

Prova dal vivo: 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"} 

Il pacchetto json può esaminare i tag per il campo e dire come mappare il campo <=> struct di json, e anche opzioni extra come se debba ignorare i campi vuoti durante la serializzazione di nuovo a json.

In sostanza, qualsiasi pacchetto può utilizzare la riflessione sui campi per esaminare i valori dei tag e agire su tali valori. C’è un po ‘più di informazioni su di loro nel pacchetto di riflessione
http://golang.org/pkg/reflect/#StructTag :

Per convenzione, le stringhe di tag sono una concatenazione di chiavi opzionalmente separate da spazio: coppie “valore”. Ogni chiave è una stringa non vuota composta da caratteri non di controllo diversi dallo spazio (U + 0020 ”), citazione (U + 0022 ‘”‘) e due punti (U + 003A ‘:’). Ogni valore è quotato usando U + 0022 caratteri “” “e syntax Go letterale stringa.