Dans le Go Language Specification , il est mentionné un bref aperçu des balises:
Une déclaration de champ peut être suivie d'une balise chaîne facultative, qui devient un attribut pour tous les champs de la déclaration de champ correspondante. Les balises sont rendues visibles via une interface de réflexion mais sont par ailleurs ignorées.
// 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" }
Ceci est une très courte explication, OMI, et je me demandais si quelqu'un pourrait me donner à quoi serviraient ces balises?
Une balise pour un champ vous permet d’attacher des méta-informations au champ qui peuvent être acquises par réflexion. Il est généralement utilisé pour fournir des informations de transformation sur la manière dont un champ struct est codé ou décodé dans un autre format (ou stocké/extrait d'une base de données), mais vous pouvez l'utiliser pour stocker les méta-informations souhaitées, destinées à un autre forfait ou pour votre propre usage.
Comme indiqué dans la documentation de reflect.StructTag
, par convention, la valeur d'une chaîne de balises est une liste de paires _key:"value"
_ séparées par un espace, par exemple:
_type User struct {
Name string `json:"name" xml:"name"`
}
_
key
désigne généralement le package auquel le _"value"
_ suivant est destiné, par exemple, les clés json
sont traitées/utilisées par le package encoding/json
.
Si plusieurs informations doivent être transmises dans _"value"
_, elles sont généralement spécifiées en les séparant par une virgule (_','
_), par exemple.
_Name string `json:"name,omitempty" xml:"name"`
_
Habituellement, une valeur de tiret (_'-'
_) pour _"value"
_ signifie d'exclure le champ du processus (par exemple, dans le cas de json
, cela signifie de ne pas marshaller ou dégrouper ce champ).
Nous pouvons utiliser la réflexion ( reflect
package) pour accéder aux valeurs de balise des champs struct. Fondamentalement, nous devons acquérir le Type
de notre structure, puis nous pouvons interroger des champs, par exemple. avec Type.Field(i int)
ou Type.FieldByName(name string)
. Ces méthodes retournent une valeur de StructField
qui décrit/représente un champ struct; et _StructField.Tag
_ est une valeur de type StructTag
qui décrit/représente une valeur de balise.
Auparavant, nous parlions de "convention" . Cette convention signifie que si vous la suivez, vous pouvez utiliser la méthode StructTag.Get(key string)
qui analyse la valeur d'une balise et vous renvoie le _"value"
_ du key
que vous spécifiez. La convention est implémentée/intégrée à cette méthode Get()
. Si vous ne suivez pas la convention, Get()
ne pourra pas analyser _key:"value"
_ paires et trouver ce que vous recherchez. Ce n'est pas non plus un problème, mais vous devez ensuite implémenter votre propre logique d'analyse.
Il y a aussi StructTag.Lookup()
(a été ajouté dans Go 1.7) qui est "comme Get()
mais distingue la balise ne contenant pas la clé donnée de la balise associant une chaîne vide à la clé donnée ".
Voyons un exemple simple:
_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"))
}
_
Sortie (essayez-le sur le 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 avait une présentation sur les balises struct appelée:
Les nombreuses facettes des balises Struct (diapositive) (et a video )
json
_ - utilisé par le package encoding/json
, détaillé à l'adresse json.Marshal()
xml
_ - utilisé par le package encoding/xml
, détaillé à l'adresse xml.Marshal()
bson
_ - utilisé par gobson , détaillé sous bson.Marshal()
protobuf
_ - utilisé par github.com/golang/protobuf/proto
, détaillé dans la documentation du paquetyaml
_ - utilisé par le package gopkg.in/yaml.v2
, détaillé à l'adresse yaml.Marshal()
db
_ - utilisé par le package github.com/jmoiron/sqlx
; également utilisé par github.com/go-gorp/gorp
paquetorm
_ - utilisé par le package github.com/astaxie/beego/orm
, détaillé à l'adresse Modèles - Beego ORMgorm
_ - utilisé par le package github.com/jinzhu/gorm
, des exemples peuvent être trouvés dans leur doc: Modèlesvalid
_ - utilisé par le package github.com/asaskevich/govalidator
, des exemples sont disponibles dans la page du projetdatastore
- utilisé par appengine/datastore
(plate-forme Google App Engine, service de banque de données), détaillé à l'adresse Propriétésschema
_ - utilisé par github.com/gorilla/schema
pour renseigner un struct
avec les valeurs de formulaire HTML détaillées dans la documentation du paquetasn
_ - utilisé par le package encoding/asn1
, détaillé sous asn1.Marshal()
et asn1.Unmarshal()
csv
_ - utilisé par le package github.com/gocarina/gocsv
Voici un exemple très simple d'utilisation de balises avec le package encoding/json
pour contrôler la façon dont les champs sont interprétés lors du codage et du décodage:
Essayez en direct: 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"}
_
Le package json peut examiner les balises du champ et savoir comment mapper le champ struct json <=>, ainsi que des options supplémentaires telles que le fait qu'il doit ou non ignorer les champs vides lors de la sérialisation en json.
Fondamentalement, tout package peut utiliser la réflexion sur les champs pour examiner les valeurs de balises et agir sur ces valeurs. Il y a un peu plus d'informations à leur sujet dans le paquet reflect
http://golang.org/pkg/reflect/#StructTag :
Par convention, les chaînes de balises sont une concaténation de paires clé: "valeur", éventuellement séparées par des espaces. Chaque clé est une chaîne non vide composée de caractères de contrôle autres que des espaces (U + 0020 ''), guillemet (U + 0022 '"') et deux points (U + 003A ':'). Chaque valeur est citée. using U + 0022 '"' caractères et la syntaxe littérale de chaîne Go.