Menu
Coddy logo textTech

Introdução a Generics

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 67 de 107.

Antes do Go 1.18, escrever código reutilizável para diferentes tipos significava duplicar funções ou usar a interface vazia any com asserções de tipo. Generics resolvem esse problema permitindo que você escreva funções e tipos que funcionam com múltiplos tipos, mantendo total segurança de tipos.

Considere encontrar o valor mínimo em um slice. Sem generics, você precisaria de funções separadas para cada tipo:

func MinInt(values []int) int {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

func MinFloat64(values []float64) float64 {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

Com generics, você escreve a lógica uma única vez usando um parâmetro de tipo em colchetes:

func Min[T int | float64](values []T) T {
    min := values[0]
    for _, v := range values {
        if v < min {
            min = v
        }
    }
    return min
}

O [T int | float64] declara um parâmetro de tipo T que pode ser tanto int quanto float64. Agora você pode chamar Min([]int{3, 1, 2}) ou Min([]float64{3.5, 1.2}) com a mesma função. O compilador verifica os tipos em tempo de compilação, para que você tenha segurança sem sobrecarga em tempo de execução.

Nas próximas lições, exploraremos parâmetros de tipo, restrições e structs genéricas em detalhes.

challenge icon

Desafio

Fácil

Vamos construir um analisador de pontuação que funcione com pontuações inteiras e de ponto flutuante usando generics! Você criará uma única função genérica que pode encontrar o valor máximo em um slice, eliminando a necessidade de código duplicado para diferentes tipos numéricos.

Você organizará seu código em dois arquivos:

  • analyzer.go: Defina sua função de análise genérica.

    Crie uma função genérica Max[T int | float64](values []T) T que encontra e retorna o valor máximo em um slice. A função deve funcionar com os tipos int e float64 através do parâmetro de tipo T.

    Crie também uma função genérica Sum[T int | float64](values []T) T que calcula e retorna a soma de todos os valores em um slice.

  • main.go: Leia a entrada e demonstre suas funções genéricas com diferentes tipos.

    Leia um indicador de tipo (int ou float), depois leia uma contagem seguida por essa quantidade de valores. Analise os valores de acordo com o tipo, chame tanto Max quanto Sum com o tipo apropriado e imprima os resultados.

    Para entrada de inteiros, imprima:

    Max (int): [value]
    Sum (int): [value]

    Para entrada de float, imprima com uma casa decimal:

    Max (float): [value]
    Sum (float): [value]

As seguintes entradas serão fornecidas:

  • Linha 1: Indicador de tipo (int ou float)
  • Linha 2: Contagem de valores (inteiro)
  • Linhas seguintes: Um valor por linha

Por exemplo, dado:

int
4
15
8
23
11

Sua saída deve ser:

Max (int): 23
Sum (int): 57

E dado:

float
3
4.5
9.2
6.8

Sua saída deve ser:

Max (float): 9.2
Sum (float): 20.5

Observe como as mesmas funções genéricas lidam com dados inteiros e de ponto flutuante—o parâmetro de tipo [T int | float64] permite que o compilador gere código seguro para tipos para cada uso, enquanto você escreve a lógica apenas uma vez.

Experimente você mesmo

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Ler o indicador de tipo
	typeStr, _ := reader.ReadString('\n')
	typeStr = strings.TrimSpace(typeStr)

	// Ler a contagem
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	if typeStr == "int" {
		// Ler valores inteiros
		values := make([]int, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.Atoi(strings.TrimSpace(line))
		}

		// TODO: Chamar Max e Sum com o slice de inteiros
		// TODO: Imprimir resultados no formato "Max (int): [value]" e "Sum (int): [value]"

	} else if typeStr == "float" {
		// Ler valores de ponto flutuante
		values := make([]float64, count)
		for i := 0; i < count; i++ {
			line, _ := reader.ReadString('\n')
			values[i], _ = strconv.ParseFloat(strings.TrimSpace(line), 64)
		}

		// TODO: Chamar Max e Sum com o slice de float64
		// TODO: Imprimir resultados com uma casa decimal no formato "Max (float): [value]" e "Sum (float): [value]"
	}
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos