Generics é um conceito utilizado em linguagens O.O em que podemos definir classes, métodos e interfaces que aceitam tipos de dados como argumento. Assim, não precisamos escrever código para cada tipo de dado.

No exemplo abaixo, sem utilizar generics, temos que declarar duas funções de adição para os tipos de dados int e float.

Exemplo 1
package main

import (
	"fmt"
)
//sem generics
func addInt(a int, b int) int {
	return a + b
}
//sem generics
func addFloat(a float32, b float32) float32 {
	return a + b
}

func main() {

	fmt.Println(addInt(1, 1))
	fmt.Println(addFloat(1.4, 1.5))
}
Saída
-

Como pode ser observado, duas funções foram codificadas para atender a adição de dois valores inteiros e floats. Como consequência, foi necessário a repetição de código do retorno em ambas as funções, por exemplo.

Fazendo uso de generics, codificamos apenas um função com os possíveis tipos de dados aceitos por uma função:

Sintaxe: função
func nome_funcao[T tipo_dado1 | tipo_dadoN]( <lista_parametros> T) T {
  //...
}
Sintaxe: variável local
var nome_variavel T
Onde
T: indicador de uso de generics
tipo_dado1..N: tipo de dado aceito como argumento para T
Exemplo 2
package main

import (
	"fmt"
)

//com generics
func add[T int | float32 | float64](a T, b T) T {
	return a + b
}

func main() {

	fmt.Println(add(1, 1))
	fmt.Println(add(1.4, 1.5))
}
Saída
2
2.9

Os tipos de dados utilizada com os parâmetros da função genérica devem suportar as operações aplicados sobre eles. No exemplo acima, a operação de adição é suportada pelos tipos numéricos. Porém, tipos complexos definidos pelo usuário não suportam esse operador.

O mesmo conceito pode ser aplicado a coleções e tipos derivados com map, array e outros. Abaixo um exemplo de somatório de valores contidos em arrays de int e float.

Exemplo 3
package main
import "fmt"

func soma[T int | float32](array []T) T {
	var total T
	for _, val := range array {
		total += val
	}
	return total
}

func main() {

	arrayInt := []int{1, 1}
	arrayFloat := []float32{1.4, 1.5}
	fmt.Println(soma(arrayInt))
	fmt.Println(soma(arrayFloat))
}
Saída
2
2.9

Fazendo uso de interface, podemos declarar uma interface que "agrupa" todos os tipos aceitos simplificando a declaração da função:

Sintaxe
type nome_interface interface {
    <lista_tipos>
}
Onde
<lista_tipos>: lista de tipos suportados separados por |
Exemplo 4
package main

import "fmt"

type Tipos interface {
	int | float32 | float64
}

func add[T Tipos](a T, b T) T {
	return a + b
}

func main() {

	fmt.Println(add(1, 1))
	fmt.Println(add(1.4, 1.5))
}
Saída
2
2.9

Go permite que o conceito de generics seja aplicado em função anônimas. Isso pode ser feito com auxílio de ponteiro para função.

Primeiro declaramos um tipo de ponteiro para função aplicando generics em seus parâmetros e retorno de acordo com a necessidade:

Exemplo 5
type ponteiro_funcao[T int | float32] func(T) T

Por fim, declaramos nossas variáveis que recebem funções anônimas que suportam o tipo ponteiro para função definido acima:

Exemplo 6
package main

import "fmt"

type ponteiro_funcao[T int | float32] func(T)

func main() {

    var funcInt ponteiro_funcao[int] = func(x int) {
        fmt.Println(x);
    }
    
    var funcFloat ponteiro_funcao[float32] = func(x float32) {
        fmt.Println(x);
    }

    funcInt(5)
    funcFloat(1.99);
 }
Saída
5
1.99

  1. 09/09/2025 - revisão 1: Reescrito; Adição: função anônima com generics
  2. 09/06/2025 - versão inicial