keywords - ¿Cuáles son los usos para las etiquetas en Go?
meta tags google (2)
En la Especificación de idioma de Go , se menciona una breve descripción de las etiquetas:
Una declaración de campo puede ir seguida de una etiqueta literal de cadena opcional, que se convierte en un atributo para todos los campos en la declaración de campo correspondiente. Las etiquetas se hacen visibles a través de una interfaz de reflexión, pero de lo contrario se ignoran.
// 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" }
Esta es una explicación muy breve de la OMI, y me preguntaba si alguien podría proporcionarme el uso de estas etiquetas.
Este es un ejemplo realmente simple de las etiquetas que se utilizan con el paquete encoding/json
para controlar cómo se interpretan los campos durante la codificación y la decodificación
Prueba en 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"}
El paquete json puede mirar las etiquetas del campo y recibir información sobre cómo asignar el campo struct json <=>, y también las opciones adicionales, como si se deben ignorar los campos vacíos al volver a serializar a json.
Básicamente, cualquier paquete puede usar la reflexión en los campos para ver los valores de las etiquetas y actuar sobre esos valores. Hay un poco más de información sobre ellos en el paquete reflect
reflect.StructTag :
Por convención, las cadenas de etiquetas son una concatenación de pares de "valores" de clave opcionalmente separados por espacios. Cada clave es una cadena no vacía que consta de caracteres que no son de control distintos del espacio (U + 0020 ''''), comillas (U + 0022 ''"'') y dos puntos (U + 003A '':''). Cada valor se cita utilizando los caracteres U + 0022 ''"'' y la sintaxis literal de la cadena Ir.
Una etiqueta para un campo le permite adjuntar metainformación al campo que puede adquirirse mediante la reflexión. Por lo general, se usa para proporcionar información de transformación sobre cómo se codifica o decodifica un campo de estructura desde otro formato (o se almacena / recupera de una base de datos), pero puede usarlo para almacenar la información meta que desee, ya sea para otra Paquete o para su propio uso.
Como se menciona en la documentación de reflect.StructTag
, por convención, el valor de una cadena de etiquetas es una lista de pares de key:"value"
separados por espacios, por ejemplo:
type User struct {
Name string `json:"name" xml:"name"`
}
Por lo general, la key
denota el paquete al que corresponde el "value"
posterior, por ejemplo, las claves json
son procesadas / utilizadas por el paquete encoding/json
.
Si se va a pasar información múltiple en el "value"
, normalmente se especifica separándola con una coma ( '',''
), por ejemplo
Name string `json:"name,omitempty" xml:"name"`
Por lo general, un valor de guión ( ''-''
) para el "value"
significa excluir el campo del proceso (por ejemplo, en el caso de json
significa no ordenar o desmarcar ese campo).
Ejemplo de acceso a sus etiquetas personalizadas mediante reflexión.
Podemos usar la reflexión (paquete de reflect
) para acceder a los valores de etiqueta de los campos de estructura. Básicamente necesitamos adquirir el Type
de nuestra estructura, y luego podemos consultar campos, por ejemplo, con Type.Field(i int)
o Type.FieldByName(name string)
. Estos métodos devuelven un valor de StructField
que describe / representa un campo de estructura; y StructField.Tag
es un valor de tipo StructTag
que describe / representa un valor de etiqueta.
Anteriormente hablamos de "convención" . Esta convención significa que si lo sigue, puede usar el StructTag.Get(key string)
que analiza el valor de una etiqueta y le devuelve el "value"
de la key
que especifique. La convención está implementada / incorporada en este método Get()
. Si no sigues la convención, Get()
no podrá analizar key:"value"
pares de key:"value"
y encontrar lo que estás buscando. Eso tampoco es un problema, pero luego necesita implementar su propia lógica de análisis.
También hay StructTag.Lookup()
(se agregó en Go 1.7) que es "como Get()
pero distingue la etiqueta que no contiene la clave dada de la etiqueta que asocia una cadena vacía con la clave dada" .
Así que veamos un ejemplo 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"))
}
Salida (pruébalo en el 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 tuvo una presentación sobre las etiquetas de estructura llamadas:
Las muchas caras de las etiquetas de Struct (diapositiva) (y un video )
Aquí hay una lista de las claves de etiquetas comúnmente usadas:
-
json
: utilizado por el paqueteencoding/json
, detallado enjson.Marshal()
-
xml
: utilizado por el paquete deencoding/xml
, detallado enxml.Marshal()
-
bson
- usado por gobson , detallado enbson.Marshal()
-
protobuf
- utilizado porgithub.com/golang/protobuf/proto
, detallado en el documento del paquete -
yaml
- utilizado por el paquetegopkg.in/yaml.v2
, detallado enyaml.Marshal()
-
db
: utilizado por el paquetegithub.com/jmoiron/sqlx
; también utilizado por el paquetegithub.com/go-gorp/gorp
-
orm
- utilizado por el paquetegithub.com/astaxie/beego/orm
, detallado en Modelos - Beego ORM -
gorm
- utilizado por el paquetegithub.com/jinzhu/gorm
, se pueden encontrar ejemplos en su documento: Models -
valid
: utilizado por el paquetegithub.com/asaskevich/govalidator
, los ejemplos se pueden encontrar en la página del proyecto -
datastore
: utilizado porappengine/datastore
(plataforma Google App Engine, servicio Datastore), detallado en Properties -
schema
: utilizado porgithub.com/gorilla/schema
para rellenar unastruct
con valores de formulario HTML, que se detalla en el documento del paquete -
asn
: utilizado por el paqueteencoding/asn1
, detallado enasn1.Marshal()
yasn1.Unmarshal()
-
csv
- utilizado por el paquetegithub.com/gocarina/gocsv