Generics em Go: para que servem e como usar na prática

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que Generics em Go são um avanço?



Por muito tempo, a linguagem Go (Golang) permaneceu uma das poucas linguagens modernas sem suporte para programação genérica (generics). Os desenvolvedores eram forçados a usar interface{} e conversão de tipos, o que levava à perda de segurança de tipos em tempo de compilação e poluía o código. Com o lançamento da versão Go 1.18 (fevereiro de 2022), a situação mudou drasticamente.



Generics (genéricos) é um mecanismo que permite escrever funções e estruturas de dados que podem trabalhar com qualquer tipo, mantendo a tipagem estrita. Neste artigo, vamos explorar para que servem e mostrar com exemplos práticos como usá-los no desenvolvimento diário com Go.



Para que servem os Generics em Go?



Antes dos genéricos, para criar funções universais, os desenvolvedores usavam interface{} (interface vazia). Vejamos um exemplo clássico — uma função que encontra o elemento mínimo em um slice:



// Sem genéricos (Go < 1.18)func MinInt(a, b int) int {    if a < b {        return a    }    return b}

func MinFloat(a, b float64) float64 { if a < b { return a } return b}


Para cada tipo, era necessário escrever uma função separada. Com interface{}, era possível fazer assim:



func MinInterface(a, b interface{}) interface{} {    // Requer conversão de tipos e verificação em tempo de execução    // Isso é inseguro e ineficiente}


Os problemas dessa abordagem são óbvios:

  • Perda de segurança de tipos — o erro pode aparecer apenas em tempo de execução.
  • Necessidade de conversão de tipos — o código se torna verboso.
  • Redução de desempenho — trabalhar com interfaces exige operações adicionais.


Generics resolvem todos esses problemas. Eles permitem:

  • Escrever algoritmos universais uma única vez.
  • Manter a verificação estrita de tipos em tempo de compilação.
  • Eliminar a conversão de tipos e melhorar o desempenho.


Fundamentos da sintaxe de Generics em Go



Os genéricos em Go são baseados em parâmetros de tipo. A sintaxe é simples e intuitiva. Os parâmetros de tipo são indicados entre colchetes após o nome da função ou tipo.



1. Função simples com genéricos



Vamos escrever a mesma função de mínimo, mas agora usando genéricos:



package main

import "fmt"

// Min retorna o valor mínimo entre doisfunc Min[T comparable](a, b T) T { if a < b { return a } return b}

func main() { fmt.Println(Min[int](10, 20)) // 10 fmt.Println(Min[float64](3.14, 2.71)) // 2.71 fmt.Println(Min[string]("abc", "xyz")) // abc}


Aqui, [T comparable] é o parâmetro de tipo. comparable é uma restrição (constraint) embutida que garante que o tipo suporta os operadores de comparação == e !=. Observe: para o operador <, é necessário usar a restrição constraints.Ordered (do pacote golang.org/x/exp/constraints) ou criar a sua própria.



2. Restrições (Constraints)



Restrições são interfaces que definem quais métodos e operações os tipos devem suportar. No Go 1.18+, foi introduzido o pacote constraints (ainda em golang.org/x/exp), mas você pode criar suas próprias restrições.



import "golang.org/x/exp/constraints"

// MinOrdered funciona apenas com tipos ordenadosfunc MinOrdered[T constraints.Ordered](a, b T) T { if a < b { return a } return b}


Restrição personalizada para tipos que suportam o método String():



Blogs

Book Recommendations