Generics en Go: para qué sirven y cómo usarlos en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿Por qué los Generics en Go son un gran avance?



Durante mucho tiempo, el lenguaje Go (Golang) fue uno de los pocos lenguajes modernos sin soporte para programación genérica (generics). Los desarrolladores se veían obligados a usar interface{} y conversiones de tipos, lo que provocaba una pérdida de seguridad de tipos en tiempo de compilación y saturaba el código. Con el lanzamiento de la versión Go 1.18 (febrero de 2022), la situación cambió drásticamente.



Generics (genéricos) es un mecanismo que permite escribir funciones y estructuras de datos que pueden trabajar con cualquier tipo, manteniendo al mismo tiempo una tipificación estricta. En este artículo, analizaremos para qué sirven y mostraremos con ejemplos prácticos cómo usarlos en el desarrollo diario con Go.



¿Para qué sirven los Generics en Go?



Antes de la aparición de los genéricos, para crear funciones universales, los desarrolladores usaban interface{} (interfaz vacía). Consideremos un ejemplo clásico: una función que encuentra el elemento mínimo en un slice:



// Sin genéricos (Go < 1.18)func MinInt(a, b int) int {    if a < b {        return a    }    return b}

func MinFloat(a, b float64) float64 { if a < b { return a } return b}


Para cada tipo había que escribir una función separada. Con interface{} se podía hacer así:



func MinInterface(a, b interface{}) interface{} {    // Se requiere conversión de tipos y verificación en tiempo de ejecución    // Esto no es seguro ni eficiente}


Los problemas de este enfoque son evidentes:

  • Pérdida de seguridad de tipos: el error puede manifestarse solo en tiempo de ejecución.
  • Necesidad de conversión de tipos: el código se vuelve voluminoso.
  • Reducción del rendimiento: trabajar con interfaces requiere operaciones adicionales.


Los Generics resuelven todos estos problemas. Permiten:

  • Escribir algoritmos universales una sola vez.
  • Mantener una verificación estricta de tipos en tiempo de compilación.
  • Eliminar las conversiones de tipos y mejorar el rendimiento.


Fundamentos de la sintaxis de Generics en Go



Los genéricos en Go se basan en parámetros de tipo. La sintaxis es simple e intuitiva. Los parámetros de tipo se indican entre corchetes después del nombre de la función o tipo.



1. Función simple con genéricos



Escribamos la misma función de mínimo, pero ahora usando genéricos:



package main

import "fmt"

// Min devuelve el valor mínimo de dosfunc Min[T comparable](a, b T) T { if a < b { return a } return b}

func main() { fmt.Println(Min[int](10, 20)) // 10 fmt.Println(Min[float64](3.14, 2.71)) // 2.71 fmt.Println(Min[string]("abc", "xyz")) // abc}


Aquí [T comparable] es el parámetro de tipo. comparable es una restricción (constraint) incorporada que garantiza que el tipo soporta los operadores de comparación == y !=. Tenga en cuenta: para el operador < se debe usar la restricción constraints.Ordered (del paquete golang.org/x/exp/constraints) o escribir la suya propia.



2. Restricciones (Constraints)



Las restricciones son interfaces que definen qué métodos y operaciones deben soportar los tipos. En Go 1.18+ apareció el paquete constraints (actualmente en golang.org/x/exp), pero usted puede crear sus propias restricciones.



import "golang.org/x/exp/constraints"

// MinOrdered funciona solo con tipos ordenadosfunc MinOrdered[T constraints.Ordered](a, b T) T { if a < b { return a } return b}


Restricción propia para tipos que soportan el método String():



Blogs

Book Recommendations