Struct Tags y Análisis Personalizado de Etiquetas
Las etiquetas de structs adjuntan metadatos declarativos a los campos.
Busca en todas las páginas de la documentación
Las etiquetas de structs adjuntan metadatos declarativos a los campos.
Las bibliotecas leen esas cadenas en tiempo de ejecución con reflexión o en tiempo de compilación con herramientas AST.
Esta página muestra cómo analizar las etiquetas json, db y validate y crear un pequeño enlazador personalizado.
Las etiquetas de structs son cadenas entre comillas invertidas después de la declaración de un campo.
El paquete reflect las expone como valores StructTag con Get y Lookup.
Los analizadores de producción validan la sintaxis, admiten múltiples claves y almacenan en caché los planes de campos por tipo.
Para rutas críticas, la generación de código lee las mismas etiquetas del código fuente y emite asignaciones directas.
Tarjeta de referencia rápida para el análisis de etiquetas.
// Declaración de campo
Name string `json:"name,omitempty" db:"user_name" validate:"required,min=2"`
// Leer una clave
tag := field.Tag.Get("json") // "name,omitempty"
name, opts, _ := strings.Cut(tag, ",")
// Buscar con indicador ok
v, ok := field.Tag.Lookup("validate") // "required,min=2", trueCuándo recurrir a esto:
go generate.Un analizador mínimo de etiquetas env que rellena un struct a partir de un mapa.
package main
import (
"fmt"
"reflect"
"strconv"
"strings"
)
type Server struct {
Host string `env:"HOST" validate:"required"`
Port int `env:"PORT" validate:"min=1"`
}
type fieldPlan struct {
index int
key string
kind reflect.Kind
}
func plans(t reflect.Type) ([]fieldPlan, error) {
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("se necesita un struct")
}
var out []fieldPlan
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !f.IsExported() {
continue
}
key, ok := f.Tag.Lookup("env")
if !ok || key == "" {
continue
}
out = append(out, fieldPlan{index: i, key: key, kind: f.Type.Kind()})
}
return out, nil
}
func bind(ptr any, env map[string]string) error {
v := reflect.ValueOf(ptr)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
return fmt.Errorf("ptr debe ser *struct")
}
v = v.Elem()
t := v.Type()
fp, err := plans(t)
if err != nil {
return err
}
for _, p := range fp {
raw, ok := env[p.key]
if !ok {
continue
}
fv := v.Field(p.index)
switch p.kind {
case reflect.String:
fv.SetString(raw)
case reflect.Int:
n, err := strconv.Atoi(raw)
if err != nil {
return fmt.Errorf("%s: %w", p.key, err)
}
fv.SetInt(int64(n))
default:
return fmt.Errorf("tipo no soportado %s para %s", p.kind, p.key)
}
}
return nil
}
func main() {
s := &Server{}
err := bind(s, map[string]string{"HOST": "0.0.0.0", "PORT": "3000"})
fmt.Println(s, err)
}Lo que esto demuestra:
Tag.Lookup distingue entre claves faltantes y valores vacíos.reflect.Type.Field(i) devuelve StructField con Name, Type, Tag y desplazamiento.StructTag.Get(key) devuelve la porción del valor antes de la primera coma para esa clave.`json:"x" xml:"x"`.| Clave | Consumidor Típico | Forma del Valor |
|---|---|---|
json | encoding/json | name,omitempty,string |
db | sqlx, GORM | nombre de columna, opciones |
validate | go-playground/validator | reglas unidas por comas |
yaml | gopkg.in/yaml.v3 | nombre yaml |
env | enlazadores personalizados | nombre de variable de entorno |
Dividir por comas, luego analizar opciones clave=valor:
func parseRules(tag string) map[string]string {
rules := map[string]string{}
for _, part := range strings.Split(tag, ",") {
k, v, ok := strings.Cut(strings.TrimSpace(part), "=")
if !ok {
rules[k] = "true"
continue
}
rules[k] = v
}
return rules
}// Almacenar planes en caché por reflect.Type en un sync.Map para frameworks
var cache sync.Map // clave: reflect.Type, valor: []fieldPlanjson:"name" causan sobrescrituras silenciosas en encoding/json. Solución: Ejecute go vet y linters personalizados en CI.fieldPlan cacheados se vuelven obsoletos si recarga tipos en plugins de larga duración. Solución: Clave la caché por identidad de tipo y documente los límites de recarga en caliente.Get devuelve "" tanto para las claves faltantes como para las vacías. Solución: Use Lookup cuando la presencia importe.
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Mapeo escrito a mano | Uno o dos DTOs | Docenas de structs similares |
go generate a partir de etiquetas | Vinculación de ruta crítica | Prototipo rápido cuya forma aún está cambiando |
| Incrustación de structs + métodos | Comportamiento ligado a tipos | Objetos de transferencia de datos puros |
Decodificador mapstructure | Mapas de configuración flexibles | Necesita etiquetas de struct estrictas por campo |
Cadena entre comillas invertidas con pares clave:"valor" separados por espacios, por ejemplo, `json:"id"`.
Los valores son siempre cadenas entre comillas.
Reflexiona sobre el tipo y lee la clave json para los nombres de campo y opciones como omitempty.
Sí.
Cualquier clave es válida; su analizador o generador la interpreta.
Algunos analizadores marcan etiquetas JSON incorrectas o etiquetas de struct sospechosas.
Habilite govet y los linters de etiquetas de struct en CI.
db nombra columnas SQL para ORMs y sqlx; json nombra campos de cableado.
El mismo struct a menudo lleva ambos.
Recorra el tipo una vez, almacene en caché los planes, reutilice en cada enlace.
La reflexión completa por solicitud está bien solo en rutas frías.
Sí.
go/ast o go/types inspeccionan las etiquetas de campo en el momento de la generación de código.
encoding/json ignora las opciones desconocidas; los analizadores personalizados deben devolver errores al inicio, no por solicitud.
No.
Son metadatos de implementación, no comentarios de documentación.
Pruebe structs de tabla con diferentes combinaciones de etiquetas y aserte los valores enlazados y los mensajes de error.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado de GC Green Tea, go fix modernizers - verifique el parche en la compilación), chi (última versión - verifique en la compilación), gin (última versión - verifique en la compilación), echo (última versión - verifique en la compilación), google.golang.org/grpc (última versión - verifique en la compilación), sigs.k8s.io/controller-runtime (última versión - verifique en la compilación), kubebuilder (última versión - verifique en la compilación), tinygo (última versión - verifique los objetivos de la placa en la compilación), wazero (última versión - verifique en la compilación) y golangci-lint (última versión - verifique el conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026