In der Go Language Specification wird eine kurze Übersicht der Tags erwähnt:
Auf eine Felddeklaration kann ein optionales String-Literal-Tag folgen, das zu einem Attribut für alle Felder in der entsprechenden Felddeklaration wird. Die Tags werden über eine Reflektionsschnittstelle sichtbar gemacht, ansonsten jedoch ignoriert.
// 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" }
Dies ist eine sehr kurze Erklärung, IMO, und ich habe mich gefragt, ob mir jemand mitteilen könnte, wozu diese Tags dienen würden.
Mit einem Tag für ein Feld können Sie Metainformationen an das Feld anhängen, die durch Reflektion erfasst werden können. Normalerweise wird es verwendet, um Transformationsinformationen darüber bereitzustellen, wie ein Strukturfeld in ein anderes Format codiert oder von einem anderen Format decodiert (oder aus einer Datenbank gespeichert/abgerufen) wird. Sie können es jedoch verwenden, um beliebige Metainformationen zu speichern, die entweder für ein anderes bestimmt sind Paket oder für Ihren eigenen Gebrauch.
Wie in der Dokumentation von reflect.StructTag
erwähnt, ist der Wert einer Tag-Zeichenfolge standardmäßig eine durch Leerzeichen getrennte Liste von key:"value"
- Paaren. Beispiel:
type User struct {
Name string `json:"name" xml:"name"`
}
Das key
bezeichnet normalerweise das Paket, für das das nachfolgende "value"
Bestimmt ist, zum Beispiel json
Schlüssel werden von encoding/json
Verarbeitet/verwendet = Paket.
Wenn im "value"
Mehrere Informationen übergeben werden sollen, werden diese normalerweise durch Trennen mit einem Komma (','
) Angegeben, z.
Name string `json:"name,omitempty" xml:"name"`
Normalerweise bedeutet ein Strichwert ('-'
) Für "value"
, Dass das Feld vom Prozess ausgeschlossen wird (z. B. im Fall von json
, dass dieses Feld nicht gemarshallt oder gemarshallt wird).
Wir können Reflection ( reflect
package) verwenden, um auf die Tag-Werte von Strukturfeldern zuzugreifen. Grundsätzlich müssen wir das Type
unserer Struktur erhalten, und dann können wir Felder abfragen, z. mit Type.Field(i int)
oder Type.FieldByName(name string)
. Diese Methoden geben den Wert StructField
zurück, der ein Strukturfeld beschreibt/darstellt. und StructField.Tag
ist ein Wert vom Typ StructTag
, der einen Tag-Wert beschreibt/darstellt.
Zuvor sprachen wir über "Konvention". Diese Konvention besagt, dass Sie die Methode StructTag.Get(key string)
verwenden können, die den Wert eines Tags analysiert und Ihnen den "value"
Des key
Sie geben an. Die Konvention ist in diese Get()
Methode implementiert/eingebaut. Wenn Sie sich nicht an die Konvention halten, kann Get()
keine key:"value"
- Paare analysieren und finden, wonach Sie suchen. Das ist auch kein Problem, aber dann müssen Sie Ihre eigene Parsing-Logik implementieren.
Es gibt auch StructTag.Lookup()
(wurde in Go 1.7 hinzugefügt), das "wie Get()
ist, aber das Tag, das den angegebenen Schlüssel nicht enthält, von dem unterscheidet Tag, das eine leere Zeichenfolge mit dem angegebenen Schlüssel verknüpft ".
Schauen wir uns also ein einfaches Beispiel an:
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"))
}
Ausgabe (versuchen Sie es auf dem 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"
Auf der GopherCon 2015 gab es eine Präsentation zu Struktur-Tags mit dem Namen:
Die vielen Gesichter von Struct-Tags (Folie) (und ein Video )
json
- Wird vom encoding/json
-Paket verwendet und unter json.Marshal()
beschriebenxml
- Wird vom encoding/xml
-Paket verwendet und unter xml.Marshal()
beschriebenbson
- verwendet von gobson , detailliert unter bson.Marshal()
protobuf
- Wird von github.com/golang/protobuf/proto
verwendet, siehe Paketdokumentationyaml
- Wird vom gopkg.in/yaml.v2
-Paket verwendet und unter yaml.Marshal()
beschriebendb
- Wird vom github.com/jmoiron/sqlx
-Paket verwendet. wird auch von github.com/go-gorp/gorp
package verwendetorm
- Wird vom github.com/astaxie/beego/orm
-Paket verwendet, ausführlich unter Models - Beego ORMgorm
- Wird vom Paket github.com/jinzhu/gorm
verwendet. Beispiele finden Sie in dessen Dokument: Modelsvalid
- Wird vom github.com/asaskevich/govalidator
-Paket verwendet. Beispiele finden Sie auf der Projektseitedatastore
- Wird von appengine/datastore
(Google App Engine-Plattform, Datenspeicherdienst) verwendet. Weitere Informationen finden Sie unter Eigenschaftenschema
- Wird von github.com/gorilla/schema
verwendet, um ein struct
mit HTML-Formularwerten zu füllen, die im Paketdokument beschrieben sindasn
- Wird vom encoding/asn1
-Paket verwendet, detailliert unter asn1.Marshal()
und asn1.Unmarshal()
csv
- Wird vom Paket github.com/gocarina/gocsv
verwendetHier ist ein wirklich einfaches Beispiel für Tags, die mit dem Paket encoding/json
verwendet werden, um zu steuern, wie Felder während der Codierung und Decodierung interpretiert werden:
Versuchen Sie es live: 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"}
Das json-Paket kann die Tags für das Feld anzeigen und erfahren, wie das json <=> struct-Feld zugeordnet wird, sowie zusätzliche Optionen, z. B., ob leere Felder bei der Serialisierung zurück zu json ignoriert werden sollen.
Grundsätzlich kann jedes Paket die Felder reflektieren, um Tag-Werte zu betrachten und auf diese Werte zu reagieren. Es gibt ein wenig mehr Informationen darüber im Reflect-Paket
http://golang.org/pkg/reflect/#StructTag :
Gemäß der Konvention sind Tag-Zeichenfolgen eine Verkettung von optional durch Leerzeichen getrennten Schlüssel: "Wert" -Paaren. Jeder Schlüssel ist eine nicht leere Zeichenfolge, die aus anderen Nicht-Steuerzeichen als Leerzeichen (U + 0020 ''), Anführungszeichen (U + 0022 '"') und Doppelpunkt (U + 003A ':') besteht. Jeder Wert wird in Anführungszeichen gesetzt Verwenden von U + 0022-Zeichen und Go-String-Literal-Syntax.