Menu
Coddy logo textTech

Introducción a los Genéricos

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy. Lección 67 de 107.

Antes de Go 1.18, escribir código reutilizable para distintos tipos significaba duplicar funciones o usar la interfaz vacía any con aserciones de tipo. Los genéricos resuelven este problema al permitirte escribir funciones y tipos que funcionan con múltiples tipos, manteniendo al mismo tiempo la seguridad de tipos completa.

Considera encontrar el valor mínimo en un slice. Sin genéricos, necesitarías funciones 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
}

Con los genéricos, escribes la lógica una sola vez usando un parámetro de tipo entre corchetes:

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

El [T int | float64] declara un parámetro de tipo T que puede ser int o float64. Ahora puedes llamar a Min([]int{3, 1, 2}) o Min([]float64{3.5, 1.2}) con la misma función. El compilador comprueba los tipos en tiempo de compilación, por lo que obtienes seguridad sin sobrecarga en tiempo de ejecución.

En las próximas lecciones, exploraremos en detalle los parámetros de tipo, las restricciones y las estructuras genéricas.

challenge icon

Desafío

Fácil

¡Construyamos un analizador de puntuaciones que funcione tanto con puntuaciones enteras como de coma flotante usando genéricos! Crearás una única función genérica que pueda encontrar el valor máximo en un slice, eliminando la necesidad de duplicar el código para distintos tipos numéricos.

Organizarás tu código en dos archivos:

  • analyzer.go: Define tu función genérica de análisis.

    Crea una función genérica Max[T int | float64](values []T) T que encuentre y devuelva el valor máximo de un slice. La función debe funcionar tanto con los tipos int como float64 mediante el parámetro de tipo T.

    Crea también una función genérica Sum[T int | float64](values []T) T que calcule y devuelva la suma de todos los valores de un slice.

  • main.go: Lee la entrada y demuestra tus funciones genéricas con distintos tipos.

    Lee un indicador de tipo (int o float), después lee una cantidad seguida de esa cantidad de valores. Analiza los valores según el tipo, llama a Max y Sum con el tipo apropiado e imprime los resultados.

    Para una entrada de tipo entero, imprime:

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

    Para una entrada de tipo flotante, imprime con una cifra decimal:

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

Se proporcionarán las siguientes entradas:

  • Línea 1: Indicador de tipo (int o float)
  • Línea 2: Cantidad de valores (entero)
  • Líneas siguientes: Un valor por línea

Por ejemplo, dada la siguiente entrada:

int
4
15
8
23
11

Tu salida debe ser:

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

Y dada la siguiente entrada:

float
3
4.5
9.2
6.8

Tu salida debe ser:

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

Observa cómo las mismas funciones genéricas gestionan tanto datos enteros como de coma flotante: el parámetro de tipo [T int | float64] permite al compilador generar código seguro respecto al tipo para cada uso, mientras tú solo escribes la lógica una vez.

Pruébalo tú mismo

package main

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

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

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

	// Leer cantidad
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

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

		// TODO: Llamar a Max y Sum con slice de enteros
		// TODO: Imprimir resultados en formato "Max (int): [value]" y "Sum (int): [value]"

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

		// TODO: Llamar a Max y Sum con slice de float64
		// TODO: Imprimir resultados con un decimal en formato "Max (float): [value]" y "Sum (float): [value]"
	}
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Go online