Conceptos básicos de reflexión
10 ejemplos para empezar con Reflexión y Generación de Código - 7 básicos y 3 intermedios.
Busca en todas las páginas de la documentación
10 ejemplos para empezar con Reflexión y Generación de Código - 7 básicos y 3 intermedios.
mkdir rfdemo && cd rfdemo && go mod init example.com/rfdemo.main.go y ejecútalos con go run ..TypeOf devuelve el tipo en tiempo de compilación de un valor como un reflect.Type.
package main
import (
"fmt"
"reflect"
)
func main() {
var n int = 42
t := reflect.TypeOf(n)
fmt.Println(t.Name(), t.Kind(), t.Size())
}TypeOf necesita un valor; usa una variable tipada o un literal.Kind() es la categoría subyacente (Int, Struct, Ptr, etc.), no el tipo con nombre.Size() informa los bytes que ocupa el tipo en memoria.Relacionado: Reflexión vs. Generación de Código en Go - cuándo la inspección en tiempo de ejecución es adecuada
ValueOf envuelve los datos reales para que puedas leerlos o mutarlos cuando sean modificables.
package main
import (
"fmt"
"reflect"
)
func main() {
s := "hello"
v := reflect.ValueOf(s)
fmt.Println(v.String(), v.Kind(), v.CanSet())
}ValueOf devuelve un reflect.Value que contiene una copia de s (no direccionable).CanSet() es falso para valores que no se pasan por puntero.Kind() para ramificar antes de llamar a métodos específicos del tipo.Relacionado: Igualdad Profunda y Cambios de Kind - envío seguro por categoría
Pasa un puntero a ValueOf, luego Elem() para alcanzar el valor subyacente.
package main
import (
"fmt"
"reflect"
)
func main() {
x := 10
v := reflect.ValueOf(&x).Elem()
fmt.Println("antes", x, v.CanSet())
v.SetInt(99)
fmt.Println("después", x)
}Elem() desreferencia punteros, slices, arrays, maps y canales.SetInt solo funciona cuando Kind() == reflect.Int y CanSet() es verdadero.Bucle NumField y Field(i) para inspeccionar cada campo exportado y no exportado de un tipo de estructura.
package main
import (
"fmt"
"reflect"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
age int // no exportado
}
func main() {
t := reflect.TypeOf(User{})
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("%s: tag=%q exportado=%v\n", f.Name, f.Tag.Get("json"), f.IsExported())
}
}Field devuelve StructField con metadatos de nombre, tipo, etiqueta y desplazamiento.Tag.Get("json") lee una clave de la cadena de etiqueta de la estructura.Relacionado: Etiquetas de Estructura y Análisis Personalizado de Etiquetas - análisis de etiquetas de validación y base de datos
Busca un campo por nombre en un Value de estructura (no solo Type).
package main
import (
"fmt"
"reflect"
)
type Point struct{ X, Y int }
func main() {
p := Point{3, 4}
v := reflect.ValueOf(p)
fx := v.FieldByName("X")
fmt.Println(fx.Int())
}FieldByName en un Value de estructura no puntero devuelve un campo no modificable.reflect.ValueOf(&p).Elem() cuando necesites Set.Value inválido; comprueba IsValid() antes de usar.Inspecciona tipos de puntero con Kind() == reflect.Ptr y Elem() para el tipo al que apunta.
package main
import (
"fmt"
"reflect"
)
func main() {
var p *int
t := reflect.TypeOf(p)
fmt.Println(t.Kind(), t.Elem().Kind())
}*int; ValueOf(nil) necesita cuidado (ver trampas en páginas hermanas).Elem() en *T produce T; en slices produce el tipo del elemento.TypeOf ve tipos instanciados.Convierte un Value de nuevo a interface{} / any cuando el tipo dinámico está exportado.
package main
import (
"fmt"
"reflect"
)
func main() {
v := reflect.ValueOf([]int{1, 2, 3})
any := v.Interface()
slice := any.([]int)
fmt.Println(slice)
}Interface() entra en pánico si el valor contiene campos no exportados y cruzas límites de paquetes.Interface() cuando conozcas el tipo.Combina Kind, NumField y Field para aplanar rutas como Address.City.
package main
import (
"fmt"
"reflect"
)
type Address struct{ City string }
type Person struct {
Name string
Addr Address
}
func walk(prefix string, v reflect.Value) {
t := v.Type()
for i := 0; i < v.NumField(); i++ {
f := t.Field(i)
fv := v.Field(i)
path := f.Name
if prefix != "" {
path = prefix + "." + f.Name
}
if fv.Kind() == reflect.Struct {
walk(path, fv)
continue
}
fmt.Println(path, fv.Interface())
}
}
func main() {
walk("", reflect.ValueOf(Person{Name: "Ada", Addr: Address{City: "London"}}))
}time.Time y tipos similares si no quieres descender en ellos.Relacionado: Creación de Generadores de Código Personalizados - reemplaza recorridos en tiempo de ejecución con código generado
Vincula datos externos de clave/valor a campos de estructura usando etiquetas o nombres.
package main
import (
"fmt"
"reflect"
"strings"
)
type Config struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
}
func applyEnv(cfg any, env map[string]string) error {
v := reflect.ValueOf(cfg)
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
return fmt.Errorf("cfg debe ser *struct")
}
v = v.Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
key := t.Field(i).Tag.Get("env")
if key == "" {
continue
}
raw, ok := env[key]
if !ok {
continue
}
fv := v.Field(i)
if fv.Kind() == reflect.String {
fv.SetString(raw)
}
if fv.Kind() == reflect.Int {
var n int
fmt.Sscanf(raw, "%d", &n)
fv.SetInt(int64(n))
}
}
return nil
}
func main() {
c := &Config{}
_ = applyEnv(c, map[string]string{"HOST": "localhost", "PORT": "8080"})
fmt.Println(c.Host, c.Port)
}CanSet() es verdadero (se requiere puntero a estructura).switch por campo para una vinculación de inicio más rápida.Relacionado: Etiquetas de Estructura y Análisis Personalizado de Etiquetas - análisis robusto de etiquetas
reflect.New(t) crea un *T con valor cero, útil para decodificar en formas desconocidas.
package main
import (
"fmt"
"reflect"
)
func main() {
t := reflect.TypeOf(0)
ptr := reflect.New(t) // *int
ptr.Elem().SetInt(7)
fmt.Println(ptr.Elem().Int())
}New siempre devuelve un Value de puntero modificable a través de Elem().*User desde reflect.TypeOf(User{}).new(T) concreto en código de aplicación; reflect.New brilla en bibliotecas genéricas.Relacionado: Costos de Reflexión de ORM y Serializador - patrones de asignación en códecs
Versiones de la pila: Esta página fue escrita para Go 1.26.x (predeterminado de GC Green Tea, modernizadores de
go fix- verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación) y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026