Generic Methods

Generic Methods: A nova forma de escrever código genérico no Go 1.27

O Go 1.27 traz uma mudança esperada por muitos desenvolvedores: métodos genéricos. Depois de anos mantendo essa funcionalidade fora da linguagem, o Go finalmente permite declarar parâmetros de tipo diretamente em métodos.
Neste post, vamos entender o que são, como usá-los e por que isso muda a forma como escrevemos código genérico.

O que são Generic Methods?

Generic methods (métodos genéricos) são métodos que declaram seus próprios parâmetros de forma genérica, independentemente da struct ser genérica. Em outras palavras, você pode ter um método com parâmetros genéricos em uma struct que não é genérica.

Antes do Go 1.27, para ter um método genérico, você precisava tornar toda a struct genérica. No entanto, agora, tudo o que você precisa fazer é colocar os parâmetros de genéricos diretamente no método onde são necessários.

A sintaxe é simples:

func (r ReceiverType) MethodName[T any](param T) T {
    // implementação
}

Diferença: Generic Functions vs Generic Methods

Desde Go 1.18, temos generic functions — funções que recebem parâmetros genéricos no escopo do pacote:

// Generic function (Go 1.18+)
func Process[T any](data T) T {
    return data
}

A limitação era que não podíamos fazer o mesmo com métodos. Se você quisesse um método genérico, tinha que tornar toda a struct genérica:

// Antes do Go 1.27 - struct inteira fica genérica
type Container[T any] struct {
    value T
}

func (c Container[T]) Get() T {
    return c.value
}

Agora, com Go 1.27, você pode deixar a struct não-genérica e colocar generics apenas no método:

// Go 1.27 - apenas o método é genérico
type Container struct {
    // atributos
}

func (c Container) Transform[T any](param T) T {
    // implementação
}

Exemplos Práticos

Agora que ficou claro como podemos utilizar essa nova feature, vamos ver mais alguns exemplos básicos.

Transformação com Map

Um caso de uso comum é o padrão Option/Maybe com um método Map genérico:

type Option[T any] struct {
    value T
    valid bool
}

// Generic method em um tipo genérico
func (o Option[T]) Map[R any](f func(T) R) Option[R] {
    if !o.valid {
        return Option[R]{valid: false}
    }
    return Option[R]{value: f(o.value), valid: true}
}

// Uso
opt := Option[int]{value: 10, valid: true}
result := opt.Map(func(x int) string {
    return fmt.Sprintf("Value: %d", x)
})

Métodos genéricos em tipos não-genéricos

Nesse segundo exemplo, escrevemos uma simples função para logar dados em formato JSON. Como o método é escrito usando generics, note que podemos utilizar uma struct ou um map como parâmetro.

type Logger struct {
    prefix string
}

// Método genérico que serializa e loga qualquer tipo
func (l Logger) LogJSON[T any](value T) error {
    data, err := json.Marshal(value)
    if err != nil {
        return err
    }
    fmt.Printf("%s: %s\n", l.prefix, string(data))
    return nil
}

// Uso
logger := Logger{prefix: "APP"}
logger.LogJSON(map[string]int{"count": 42})
logger.LogJSON(struct{ Name string }{"Alice"})

Casos de Uso

1. APIs fluentes e builders
Métodos genéricos são perfeitos para padrões builder e fluent interfaces onde cada método pode trabalhar com tipos diferentes.

2. Transformação de dados
Como vimos com Map, é comum transformar dados de um tipo para outro, mantendo contexto (como Option ou Result).

3. Serialização e logging
Métodos que precisam serializar ou processar valores de qualquer tipo, sem tornar toda a estrutura genérica.

4. Operações em coleções
Filter, Map, Reduce em slices, maps ou estruturas customizadas.

Limitações Importantes

Nem tudo é possível com generic methods. Existem restrições deliberadas:

  • Métodos de interfaces não podem ser genéricos: Uma interface não pode declarar métodos genéricos. Isso mantém a simplicidade de satisfação de interfaces.
// Isso não compila!
type Reader interface {
    Read[T any](ctx context.Context) (T, error)
}
  • Implementações genéricas de métodos não-genéricos: Você não pode implementar um método não-genérico de uma interface com um método genérico.
  • Sem sobrecarga de métodos: Go não suporta sobrecarga, então você não pode ter dois métodos com o mesmo nome e parâmetros de tipo diferentes.

Conclusão

Generic methods no Go 1.27 eliminam uma das maiores limitações dos generics introduzidos em 1.18, trazendo liberdade para escrever APIs mais limpas, sem precisar tornar as structs inteiras genéricas quando apenas seus métodos precisam dessa funcionalidade.

Isso é especialmente valioso para bibliotecas e código que trabalha com transformação de dados, onde aplicar generics em nível de struct era overkill. Com essa mudança, o Go fica ainda mais expressivo e flexível.

Comece a experimentar essa funcionalidade quando Go 1.27 for lançado (agosto de 2026) e modernize suas APIs!


Gostou do conteúdo?

  • Inscreva-se na newsletter para receber mais dicas práticas sobre Go diretamente no seu e-mail!
  • 🚀 Conheça a Imersão Golang e leve seus conhecimentos em Go para o próximo nível!

Faça parte da comunidade!

Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.

* indicates required

Deixe uma resposta