Structs, Embedding e Promoção de Campos
Structs agrupam campos nomeados em um único tipo.
Busque em todas as páginas da documentação
Structs agrupam campos nomeados em um único tipo.
Embedding permite compor comportamento e campos de outros tipos sem herança, promovendo membros exportados para o tipo externo.
Uma literal de struct define campos por nome ou posição (se não ambíguo).
Campos incorporados devem ser sem nome e o nome do tipo se torna um nome de campo para promoção.
Campos e métodos promovidos são chamáveis no valor externo como se declarados ali, a menos que sejam ocultados.
Cartão de receita de referência rápida - pronto para copiar e colar.
package main
import "fmt"
type Logger struct{}
func (Logger) Log(msg string) { fmt.Println(msg) }
type Server struct {
Logger
Addr string
}
func main() {
s := Server{Addr: ":8080"}
s.Log("listening") // método promovido
fmt.Println(s.Addr)
}Quando usar isso:
User, Order, Config).io.Reader, sync.Mutex).package main
import "fmt"
type Person struct {
Name string
Age int
}
type Employee struct {
Person
ID int
Dept string
}
func (p Person) Greet() string {
return "hello, " + p.Name
}
func describe(e Employee) {
fmt.Println(e.Name, e.ID, e.Greet())
}
func main() {
e := Employee{
Person: Person{Name: "Ada", Age: 36},
ID: 1001,
Dept: "research",
}
describe(e)
// Campo externo explícito vence sobre o promovido se os nomes colidirem
type Shadow struct {
Person
Name string
}
sh := Shadow{Person: Person{Name: "Grace"}, Name: "Override"}
fmt.Println(sh.Name, sh.Person.Name)
}O que isso demonstra:
Person incorporado para Employee.e.Name acessa Person.Name incorporado.| Forma | Exemplo | Quando |
|---|---|---|
| Campos nomeados | Person{Name: "Ada"} | Padrão - claro e sem ordem |
| Posicional | Person{"Ada", 36} | Apenas structs pequenas e estáveis |
| Literal de ponteiro | &Person{Name: "Ada"} | APIs que esperam *Person |
| Parcial | Person{Name: "Ada"} | Outros campos zerados |
| Situação | Resultado |
|---|---|
T incorporado único | outer.Field se T.Field for exportado |
Método em T | Chamável como outer.Method() |
| Colisão de nomes no externo | Campo externo oculta; use outer.T.Field |
| Múltiplas incorporações em conflito | Acesso ambíguo - erro do compilador sem qualificador |
// Incorpora interface para encaminhar comportamento
type ReadCloser struct {
io.Reader
io.Closer
}
// Incorpora mutex - valor zero utilizável
type SafeMap struct {
sync.Mutex
m map[string]int
}*T incorporado com nil causa pânico na chamada de método promovido. Correção: garanta a inicialização ou proteja as chamadas.encoding/json por padrão. Correção: nomeie campos ou ajuste tags quando a aninhamento for importante.==; compare os campos manualmente.Name se aplica. Correção: evite nomes de campo duplicados entre tipos externos e incorporados.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Campo nomeado person Person | Propriedade clara, sem promoção | Você quer métodos promovidos |
| Embedding | Composição real do tipo "é um" (Server tem logging) | Apenas agrupamento de dados simples |
| Interfaces | Abstração de comportamento | Você só precisa de campos de dados |
| Pacotes separados | Ocultar implementação incorporada | Auxiliares locais apertados |
Campos e métodos exportados de um tipo incorporado aparecem no tipo externo sem um qualificador.
e.Name funciona quando Person é incorporado e tem Name.
Sim, se os nomes promovidos não conflitarem.
Promoções ambíguas exigem seletores explícitos como e.Person.Name.
O campo incorporado é um campo real armazenado dentro da struct externa por valor (ou ponteiro se *T).
Não é um link de referência.
Se T tem func (t *T) M(), o O externo com T incorporado obtém M quando O ou *O é endereçável de acordo com as regras do receptor.
Você só pode incorporar tipos nomeados, não int puro.
Defina type UserID int e incorpore UserID se necessário.
Campos de struct anônimos são marshalados inline (campos promovidos para o nível superior), a menos que a tag json:",inline" altere o comportamento para structs aninhadas.
Campos nomeados aninham normalmente.
Tipo marcador de tamanho zero usado para chaves de conjunto map[K]struct{} e canais de sinalização.
Ele não aloca bytes adicionais para o valor.
Tags são metadados de string lidos via reflexão (reflect.StructTag).
Pacotes como encoding/json e ORMs os interpretam em tempo de execução.
Somente se todos os campos forem comparáveis.
Slices, mapas e funções internas quebram a comparabilidade.
A atribuição copia tipos de valor campo a campo.
Para campos de ponteiro, a cópia duplica ponteiros - faça uma cópia profunda manualmente se necessário.
Use *T ao mutar, evitar custo de cópia para structs grandes ou representar presença opcional.
Registros imutáveis pequenos podem permanecer como valores.
Incorporar unexportedType promove apenas para tipos no mesmo pacote.
Pacotes externos não podem acessar membros não exportados promovidos.
Versões de Stack: Esta página foi escrita para Go 1.26.x (GC padrão Green Tea, modernizadores go fix - 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: 19 de jul. de 2026