Generics em Go (1.18+)
- ⬜⚠️ Error handling: explicit + errors.Is/As(Go Profissional)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Generics chegaram em 1.18 com sintaxe enxuta
📋 Escrever uma função genérica ou uma concreta
O parâmetro de tipo só se paga quando existem, hoje, dois ou mais tipos passando pela mesma função. Antes disso ele acrescenta ruído na assinatura para resolver um caso hipotético — e a biblioteca padrão já cobre a maior parte dos utilitários de fatia e mapa.
Alt: Genérica desde o início — Assinatura mais difícil de ler para um caso que nunca variou
Alt: Interface vazia com asserção — Perde a verificação de tipo e move o erro para execução
Alt: Duplicar a função por tipo — Aceitável para dois tipos; vira manutenção acima disso
Type parameters entram entre colchetes após o nome da função ou tipo. Constraints são interfaces que listam tipos ou métodos permitidos. Em 1.21 entrou slices, maps e cmp na stdlib, com operações genéricas prontas. Em 2026 o uso maduro é: container e utilitários genéricos, código de domínio concreto.
Primeiros exemplos
func Map[T, U any](s []T, f func(T) U) []U {
out := make([]U, len(s))
for i, v := range s {
out[i] = f(v)
}
return out
}
doubled := Map([]int{1, 2, 3}, func(n int) int { return n * 2 })
names := Map(users, func(u User) string { return u.Name })Constraints
// any é alias de interface{}
func Reduce[T, A any](s []T, init A, f func(A, T) A) A { ... }
// comparable habilita == e !=
func Contains[T comparable](s []T, v T) bool {
for _, x := range s {
if x == v { return true }
}
return false
}
// Constraint custom com union de tipos (Go 1.18+)
type Numeric interface {
~int | ~int32 | ~int64 | ~float32 | ~float64
}
func Sum[T Numeric](s []T) T {
var total T
for _, v := range s { total += v }
return total
}O ~ permite tipos derivados: type Money int64 ainda satisfaz ~int64. Sem ~ aceitaria apenas o tipo exato.
Pacotes slices, maps e cmp (1.21+)
import (
"cmp"
"slices"
"maps"
)
s := []int{3, 1, 4, 1, 5}
slices.Sort(s) // ordena in place
i, ok := slices.BinarySearch(s, 4) // busca binária
s = slices.Compact(s) // remove duplicados consecutivos
m := map[string]int{"a": 1, "b": 2}
keys := slices.Sorted(maps.Keys(m)) // keys ordenadas
type User struct{ Name string; Age int }
slices.SortFunc(users, func(a, b User) int {
return cmp.Compare(a.Age, b.Age)
})O que o til em uma restrição como `~int64` habilita?
Quando usar, quando não usar
Use: container genérico (queue, set, LRU), helpers de slice/map, funções matemáticas, cache tipado. Stdlib do 1.21+ resolve a maior parte sem precisar escrever seu próprio.
Evite: transformar toda função utility em generic só por hábito de outra linguagem. Se o tipo está fixo (User, Order), concreto é mais legível. Se a abstração "funciona pra qualquer T" é real, aí generics valem.
Performance
Go não faz monomorphization completa como C++/Rust. Usa mistura de dictionary passing e gcshape stenciling — um pouco mais lento que monomorphization em micro benchmark, mas quase imperceptível em código real. Se perf importa num hot path, benchmark sempre.
Perguntas frequentes
❓ Quando usar genéricos em Go?
❓ Genéricos substituíram interface vazia?
❓ Genérico piora o desempenho?
Fixando
Qual é o critério do módulo para NÃO escrever uma função genérica?
Depois dos pacotes genéricos de slice e mapa entrarem na biblioteca padrão, o que mudou para quem escreve utilitários?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…