Menu
CoddyTech

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 tipos 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 genéricos, 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 detalhadamente 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 funciona tanto com pontuações inteiras quanto com números de ponto flutuante usando genéricos! Você criará uma única função genérica que encontra 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 encontra e retorna o valor máximo em uma fatia. A função deve funcionar tanto com os tipos int quanto 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 calcula e retorna 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) e, em seguida, leia uma quantidade seguida desse número 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 de inteiros, imprima:

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

    Para uma entrada de números 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, dada a entrada:

int
4
15
8
23
11

Sua saída deve ser:

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

E dada a entrada:

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)

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

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

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

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

	} else if typeStr == "float" {
		// Leia os 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: Chame Max e Sum com o slice de float64
		// TODO: Imprima os 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