Quando Evitar Generics em APIs Go
Nem toda função exportada precisa de sintaxe de colchetes.
Busque em todas as páginas da documentação
Nem toda função exportada precisa de sintaxe de colchetes.
Esta folha de dicas lista situações em que interfaces, tipos concretos ou pequenas duplicações mantêm as APIs públicas idiomáticas e mais fáceis de evoluir.
| Sinal | Prefira em vez disso | Exemplo |
|---|---|---|
| Um único tipo concreto em produção | Função não genérica | ParseConfig(cfg Config) em vez de Parse[T Config](T) |
| Contrato de comportamento, muitas implementações | Pequena interface | io.Reader, Validator |
| Assinatura de handler HTTP/gRPC | Tipos concretos de requisição/resposta | func(w http.ResponseWriter, r *http.Request) |
| Extensibilidade de plugin ou de terceiros | Interface + registro | Cadeias de middleware em chi / gin / echo |
| Esquema JSON/dinâmico | any + etapa de decodificação tipada | json.Unmarshal em uma struct |
| Cheiro | Por que evitar generics | Melhor forma |
|---|---|---|
| Colchetes em todos os nomes de auxiliares | Dificulta grep e documentação | sortItems[T] não exportado por trás de SortItems exportado |
| Restrição com 8+ membros de união | Limite instável e ilegível | Tipo de domínio nomeado ou divisão não genérica |
| Structs genéricas exportadas que os usuários nunca parametrizam | Ruído na API | Struct concreta ou campo de interface |
| Mudança de restrição quebra chamadores silenciosamente em tempo de compilação | Grande raio de explosão | Superfície de interface estável, genéricos internos |
| Duplicatas de teste precisam de muitas instanciações | Proliferação de mocks | Limite de interface |
| Contexto | Risco de Generics | Orientação |
|---|---|---|
| WASM / tinygo | Múltiplas instanciações inflacionam o binário | Um caminho de código ou codegen limitado |
| Caminho crítico já usa interfaces para plugins | Ganho genérico marginal | Benchmark antes da reescrita |
| Desalinhamento de versão entre módulos | Símbolos de instanciação se multiplicam | Mantenha generics em pacotes folha |
| Frameworks baseados em reflection | Generics não simplificam reflection | Mantenha-se com interfaces |
| Pergunta | Se sim | Se não |
|---|---|---|
Os chamadores usarão mais de um T? | Candidato a genérico | API concreta |
| Isso é exportado? | Favoreça superfície mais simples | Genérico interno OK |
T precisa de métodos de domínios diferentes? | Interface, não união | Restrição mais restrita |
| A legibilidade para desenvolvedores juniores é um objetivo? | Evite exports com muitos colchetes | Uso interno OK |
| A biblioteca padrão já fornece um auxiliar? | Use slices/maps/cmp | Genérico customizado |
| Objetivo | Evitar | Preferir |
|---|---|---|
| Ordenar usuários por idade | func Sort[T any]([]T, func(T,T) bool) exportado | slices.SortFunc(users, cmp.Compare) localmente |
| Validar modelos | Validate[T Validator](T) com restrição enorme | type Validator interface { Validate() error } |
| Obter do repositório | Get[T any](id string) (T, error) público | GetUser(id string) (User, error) |
Sim - a biblioteca padrão mantém as APIs públicas majoritariamente não genéricas e usa generics internamente em slices, maps e cmp.
Siga essa divisão.
Raramente - frameworks expõem contextos e interfaces concretas.
Mantenha generics em utilitários internos compartilhados.
Get[T] tenta, mas espalha a sintaxe de colchetes e aperta as restrições nos modelos.
Prefira métodos de domínio por agregado.
Apenas quando pacotes downstream precisam definir generics compatíveis.
Caso contrário, mantenha as restrições não exportadas.
Auxiliares de lote internos e utilitários de teste - não a superfície gerada por .proto.
Código gerado permanece concreto.
Não - tipos concretos e interfaces são verificados estaticamente.
Generics são uma ferramenta, não a única ferramenta segura.
Reconciliadores permanecem orientados por interface contra tipos client-go.
Use generics em pequenos auxiliares de lista/deduplicação dentro do projeto.
Lidere com interfaces simples e tipos concretos.
Adicione generics mais tarde sem quebrar a superfície quando possível.
Exportado: Process(items []Item).
Não exportado: dedupe[T comparable]([]T) []T.
Duas funções concretas com cinco linhas cada batem uma genérica com união de dez membros.
Versõ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: 18 de jul. de 2026