Noções Básicas de Reflexão
10 exemplos para você começar com Reflexão e Codegen - 7 básicos e 3 intermediários.
Busque em todas as páginas da documentação
10 exemplos para você começar com Reflexão e Codegen - 7 básicos e 3 intermediários.
mkdir rfdemo && cd rfdemo && go mod init example.com/rfdemo.main.go e execute com go run ..TypeOf retorna o tipo em tempo de compilação de um valor como um 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 precisa de um valor; use uma variável tipada ou um literal.Kind() é o tipo subjacente (Int, Struct, Ptr, etc.), não o tipo nomeado.Size() relata os bytes que o tipo ocupa na memória.Relacionado: Reflexão vs. Geração de Código em Go - quando a inspeção em tempo de execução se encaixa
ValueOf encapsula os dados reais para que você possa lê-los ou mutá-los quando forem definíveis.
package main
import (
"fmt"
"reflect"
)
func main() {
s := "hello"
v := reflect.ValueOf(s)
fmt.Println(v.String(), v.Kind(), v.CanSet())
}ValueOf retorna um reflect.Value contendo uma cópia de s (não endereçável).CanSet() é falso para valores que não foram passados por ponteiro.Kind() para ramificar antes de chamar métodos específicos do tipo.Relacionado: Igualdade Profunda e Switches de Kind - despacho seguro por tipo
Passe um ponteiro para ValueOf, então Elem() para alcançar o valor subjacente.
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("depois", x)
}Elem() desreferencia ponteiros, slices, arrays, maps e canais.SetInt funciona apenas quando Kind() == reflect.Int e CanSet() é verdadeiro.Percorra NumField e Field(i) para inspecionar cada campo exportado e não exportado de um tipo struct.
package main
import (
"fmt"
"reflect"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
age int // não 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 retorna StructField com nome, tipo, tag e metadados de offset.Tag.Get("json") lê uma chave da string da tag do struct.Relacionado: Tags de Struct e Análise Personalizada de Tags - análise de tags de validação e banco de dados
Procure um campo por nome em um Value de struct (não apenas 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 em um Value de struct não ponteiro retorna um campo não definível.reflect.ValueOf(&p).Elem() quando precisar de Set.Value inválido; verifique IsValid() antes de usar.Inspecione tipos de ponteiro com Kind() == reflect.Ptr e Elem() para o tipo apontado.
package main
import (
"fmt"
"reflect"
)
func main() {
var p *int
t := reflect.TypeOf(p)
fmt.Println(t.Kind(), t.Elem().Kind())
}*int; ValueOf(nil) requer cuidado (veja armadilhas nas páginas irmãs).Elem() em *T produz T; em slices produz o tipo do elemento.TypeOf vê tipos instanciados.Converta um Value de volta para interface{} / any quando o tipo dinâmico for 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 em pânico se o valor contiver campos não exportados e você cruzar limites de pacotes.Interface() quando você souber o tipo.Combine Kind, NumField e Field para achatar caminhos 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 e tipos semelhantes se você não quiser descer neles.Relacionado: Construindo Geradores de Código Personalizados - substitua caminhadas em tempo de execução por código gerado
Vincule dados externos de chave/valor a campos de struct usando tags ou nomes.
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 must be *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() for verdadeiro (ponteiro para struct necessário).Relacionado: Tags de Struct e Análise Personalizada de Tags - análise robusta de tags
reflect.New(t) cria um *T com valor zero, útil para decodificar em formas desconhecidas.
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 sempre retorna um Value de ponteiro definível via Elem().*User de reflect.TypeOf(User{}).new(T) concreto no código da aplicação; reflect.New brilha em bibliotecas genéricas.Relacionado: Custos de Reflexão de ORM e Serializador - padrões de alocação em codecs
Versões da Stack: Esta página foi escrita para Go 1.26.x (padrão GC Green Tea, go fix modernizers - verifique o patch na compilação), chi (última versão - verifique na compilação), gin (última versão - verifique na compilação), echo (última versão - verifique na compilação), google.golang.org/grpc (última versão - verifique na compilação), sigs.k8s.io/controller-runtime (última versão - verifique na compilação), kubebuilder (última versão - verifique na compilação), tinygo (última versão - verifique os alvos de placa na compilação), wazero (última versão - verifique na compilação) e golangci-lint (última versão - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 18 de jul. de 2026