Genéricos em Go: Restrições Sem Templates
Go adicionou parâmetros de tipo no Go 1.18 para que você possa escrever funções e tipos que funcionam com muitos tipos concretos, mantendo a segurança de tipo em tempo de compilação.
Busque em todas as páginas da documentação
Go adicionou parâmetros de tipo no Go 1.18 para que você possa escrever funções e tipos que funcionam com muitos tipos concretos, mantendo a segurança de tipo em tempo de compilação.
O design é deliberadamente mais simples que os sistemas de templates em C++ ou Java.
Restrições são tipos de interface comuns (com conjuntos de tipos), não uma linguagem de template separada.
Esta página é a âncora conceitual para a seção de Genéricos.
Noções Básicas de Genéricos coleta trechos executáveis; artigos irmãos cobrem sintaxe de restrição, comparable, estruturas de dados, utilitários da biblioteca padrão e trade-offs de desempenho.
T) representa um tipo concreto em tempo de compilação, e uma interface de restrição limita quais tipos podem substituir T.interface{} (hoje any), boilerplate de go generate e cópias de utilitários para slices, mapas e contêineres sem abrir mão da tipagem estática.interface{} ou codegen.slices/maps/cmp da biblioteca padrão, reflection.Antes do Go 1.18, código reutilizável frequentemente usava interface{} (hoje any), interfaces pequenas ou go generate para gerar cópias por tipo.
Cada abordagem trocava segurança ou clareza por flexibilidade.
Genéricos adicionam listas de tipos entre colchetes a funções e tipos: func Max[T cmp.Ordered](a, b T) T.
O compilador verifica se cada tipo de argumento satisfaz a restrição antes de aceitar a chamada.
Uma restrição é um tipo de interface.
Ela pode listar métodos (interface { String() string }), nomear tipos em uma união (int | float64), ou usar o operador de tipo subjacente ~int (qualquer tipo cujo tipo subjacente seja int, incluindo tipos inteiros nomeados).
As restrições pré-declaradas any (todos os tipos) e comparable (tipos permitidos com == e !=) cobrem os casos mais comuns.
A instanciação é explícita ou inferida: Max[int](1, 2) ou Max(1, 2) quando o compilador pode inferir T.
Ao contrário dos templates C++, Go não tem fase de expansão de macro nem ganchos de especialização definidos pelo usuário.
O compilador monomorfiza: ele gera código de máquina (ou IR) especializado para cada instanciação distinta, semelhante em espírito a gerar MaxInt, MaxFloat64, e assim por diante manualmente.
A verificação de tipo ocorre em duas fases.
Tempo de definição: o corpo da função genérica só pode usar operações permitidas para todos os tipos no conjunto de tipos da restrição.
Se T for apenas int | float64, você não pode chamar T.String() a menos que a restrição inclua esse método.
Tempo de instanciação: cada local de chamada substitui tipos concretos.
Se nenhuma substituição válida existir, a compilação falha com um erro de restrição claro, em vez de um pânico em tempo de execução de uma type assertion incorreta.
// Restrição: Tipos Ordenados de cmp - int, float, string, etc.
func Min[T cmp.Ordered](a, b T) T {
if a < b {
return a
}
return b
}Conjuntos de tipos são o conjunto de tipos que uma restrição aceita.
~byte | ~rune aceita tanto byte quanto tipos nomeados personalizados com esses tipos subjacentes.
Elementos de união devem ser comparáveis entre si quando a restrição é usada em contextos que exigem isso (por exemplo, chaves de mapa precisam de comparable).
Genéricos interagem com interfaces de forma limpa: um parâmetro de tipo restrito a uma interface ainda usa a satisfação implícita de interface do Go.
Eles não introduzem herança nominal.
Métodos não podem declarar seus próprios parâmetros de tipo em Go; apenas funções e tipos nomeados no nível do pacote carregam listas de parâmetros de tipo.
Métodos em tipos genéricos usam os parâmetros do tipo (func (s *Stack[T]) Push(v T)).
definição genérica local de chamada
------------------ ----------------
func Map[F,T any](...) --> Map[string,int](...)
| |
v v
verificação de restrição Map_string_int
em F, T monomorfizado
| Abordagem | Força | Fraqueza | Melhor Encaixe |
|---|---|---|---|
| Genéricos | Tipagem estática, sem casts | Ruído na sintaxe, tamanho do binário | Algoritmos de Slice/mapa, contêineres |
| Interfaces pequenas | APIs idiomáticas do Go | Despacho em tempo de execução, boilerplate | IO, plugins, contratos de comportamento |
any + type switch | Análise flexível | Erros em tempo de execução, verboso | Adaptadores JSON, impressoras de depuração |
go generate | Custo zero em tempo de execução, tipos explícitos | Complexidade da etapa de compilação | Caminhos críticos de alta performance com muitos tipos |
| Reflection | Uma implementação | Lento, sem verificações de compilação | Plugins, esquemas desconhecidos |
Bibliotecas como chi, gin e echo raramente expõem assinaturas de handler genéricas; genéricos brilham em utilitários internos (helpers de paginação, caches tipados) e utilitários compartilhados de middleware do google.golang.org/grpc, não em todas as assinaturas de rota públicas.
Projetos controller-runtime e kubebuilder frequentemente combinam codegen (para CRDs) com helpers de lista genéricos em pacotes compartilhados.
tinygo e wazero têm suporte variável por alvo; verifique código com muitos genéricos em builds embarcados e WASM no CI.
golangci-lint pode sinalizar parâmetros de tipo redundantes e APIs excessivamente genéricas; combine genéricos com benchmarks quando o tamanho do binário for importante (veja Implicações de Desempenho).
Adoção gradual é idiomática: comece com helpers não exportados, depois expanda APIs quando as restrições se estabilizarem.
Prefira os pacotes da biblioteca padrão slices, maps e cmp antes de manter cópias personalizadas.
Quando uma restrição cresce para mais de três uniões, extraia um tipo de restrição nomeado (type Number interface { ~int \| ~float64 }) para legibilidade.
any significa que posso fazer qualquer coisa com T - Você pode armazenar qualquer valor, mas ainda não pode usar == em T a menos que a restrição seja comparable, e você não pode chamar métodos não listados na restrição.Go 1.18 adicionou parâmetros de tipo, interfaces de restrição com conjuntos de tipos e inferência em locais de chamada.
Não adicionou métodos genéricos em tipos não genéricos, especialização de template ou sobrecarga de operador.
O conjunto de tipos é a coleção de tipos concretos permitidos para substituir um parâmetro de tipo.
Interfaces de restrição definem esse conjunto através de métodos, tipos subjacentes ~T e uniões |.
Interfaces já eram o mecanismo de composição do Go.
Reutilizá-las para restrições mantém uma notação para "quais operações T suporta?" em vez de inventar um segundo sistema de tipos.
O compilador emite código especializado para cada argumento de tipo distinto (por exemplo, Stack[int] vs Stack[string]).
Cada versão é verificada quanto ao tipo independentemente, como duplicatas escritas à mão.
Chaves de mapa, alguns primitivos de sincronização e qualquer algoritmo que use == em T precisam de comparable.
Slices, mapas e funções não são comparáveis em Go.
Métodos em um tipo genérico usam os parâmetros do tipo.
Você não pode adicionar uma nova lista de parâmetros de tipo a um método comum em um tipo não genérico.
A inferência funciona quando os tipos dos argumentos fixam cada parâmetro.
Quando falha, passe argumentos de tipo explícitos: Convert[int](v).
Uma restrição pode exigir métodos; tipos concretos satisfazem implicitamente.
Um parâmetro de tipo restrito a io.Reader aceita qualquer implementação de reader sem herança.
Go 1.21 adicionou os pacotes genéricos slices, maps e cmp.
Prefira-os antes de cópias personalizadas.
Noções Básicas de Genéricos para exemplos, depois Parâmetros de Tipo e Interfaces de Restrição para sintaxe ~ e uniões.
O conteúdo conceitual se aplica aos genéricos do Go 1.18+.
Exemplos da biblioteca padrão assumem Go 1.21+ para slices/maps/cmp.
Os designers priorizaram simplicidade, compilações rápidas e erros legíveis em vez do poder de metaprogramação do nível C++.
Restrições mantêm APIs genéricas fáceis de buscar e revisar.
~ e uniõesVersões de Stack: Esta página foi escrita para Go 1.26.x (padrão Green Tea GC, 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: 19 de jul. de 2026