Menu
Coddy logo textTech

Introdução aos genéricos

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. Os genéricos resolvem esse problema permitindo que você escreva funções e tipos que funcionam com vários tipos, mantendo a segurança de tipos completa.

Considere encontrar o valor mínimo em uma fatia. Sem genéricos, 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 vez usando um parâmetro de tipo entre 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 int ou 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, então você obtém segurança sem sobrecarga em tempo de execução.

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

challenge icon

Desafio

Fácil

Vamos criar um analisador de pontuações que funcione com pontuações inteiras e de ponto flutuante usando genéricos! Você criará uma única função genérica que pode encontrar o valor máximo em uma fatia, 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 genérica de análise.

    Crie uma função genérica Max[T int | float64](values []T) T que encontre e retorne o valor máximo em uma fatia. A função deve funcionar com os tipos int e float64 por meio do parâmetro de tipo T.

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

  • 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 quantidade seguida por essa quantidade de valores. Analise os valores de acordo com o tipo, chame Max e Sum com o tipo apropriado e imprima os resultados.

    Para uma entrada inteira, imprima:

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

    Para uma entrada de ponto flutuante, 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: Quantidade de valores (inteiro)
  • Linhas seguintes: Um valor por linha

Por exemplo, considerando:

int
4
15
8
23
11

Sua saída deve ser:

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

E considerando:

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 quanto aos 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 indicador de tipo
	typeStr, _ := reader.ReadString('\n')
	typeStr = strings.TrimSpace(typeStr)

	// Ler 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 slice de inteiros
		// TODO: Imprimir resultados no formato "Max (int): [value]" e "Sum (int): [value]"

	} else if typeStr == "float" {
		// Ler valores float
		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 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

Pratique por conta própria: Compilador de Go online