Adición de Genéricos en Golang

 

Genéricos en Go

Genéricos en Go 🧬🐹

Es en una de las adiciones más emocionantes a Go desde su creación: los genéricos. Introducidos en Go 1.18, los genéricos han abierto un mundo de posibilidades para escribir código más flexible y reutilizable. ¡Vamos a descubrir cómo pueden revolucionar tu código!

¿Qué son los Genéricos? 🤔

Los genéricos te permiten escribir funciones y tipos que pueden trabajar con diferentes tipos de datos. Es como tener una receta de cocina que funciona igual de bien con diferentes ingredientes.

¿Por qué Necesitábamos Genéricos? 🎯

Antes de los genéricos, el mundo era triste, desolado, y a menudo teníamos que elegir entre:

  1. Escribir código específico para cada tipo.
  2. Usar interface{} (que es como usar any en Typescript) y perder la seguridad de tipos.

Veamos un ejemplo del mundo triste y desolado:

// Antes de los genéricos, nota que la primera función es para Ints // Luego para Floats y así infinitamente para cada tipo que se quiera 😵‍💫 func SumInts(numbers []int) int { sum := 0 for _, n := range numbers { sum += n } return sum } func SumFloats(numbers []float64) float64 { sum := 0.0 for _, n := range numbers { sum += n } return sum }

¡Mucha repetición! Y si quisiéramos sumar otros tipos, tendríamos que escribir una nueva función para cada uno.

Genéricos al Rescate 🦸‍♂️

Con genéricos, podemos escribir una sola función que funcione para múltiples tipos:

func Sum[T int | float64](numbers []T) T { var sum T for _, n := range numbers { sum += n } return sum }

¡Ahora podemos usar la misma función para sumar enteros o flotantes!

ints := []int{1, 2, 3, 4} floats := []float64{1.1, 2.2, 3.3, 4.4} fmt.Println(Sum(ints)) // 10 fmt.Println(Sum(floats)) // 11.0

Tipos Genéricos 🧱

No solo las funciones pueden ser genéricas. También podemos crear tipos genéricos:

type Stack[T any] struct { items []T } func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) } func (s *Stack[T]) Pop() (T, bool) { if len(s.items) == 0 { var zero T return zero, false } item := s.items[len(s.items)-1] s.items = s.items[:len(s.items)-1] return item, true }

Ahora podemos crear pilas de cualquier tipo:

intStack := &Stack[int]{} intStack.Push(1) intStack.Push(2) stringStack := &Stack[string]{} stringStack.Push("hello") stringStack.Push("world")

Restricciones de Tipo 🚧

Podemos usar restricciones para limitar qué tipos pueden usarse con nuestros genéricos:

type Number interface { int | float64 } func Max[T Number](a, b T) T { if a > b { return a } return b }

Esta función Max solo funcionará con tipos que satisfagan la interfaz Number.

Ventajas de los Genéricos 🌟

  1. Código más DRY: Evitas repetir lógica similar para diferentes tipos.
  2. Seguridad de tipos: Mantienes la seguridad de tus tipos.
  3. Flexibilidad: Escribes código más adaptable y reutilizable.
  4. Mejor rendimiento: Comparado con usar interface{}, los genéricos ofrecen mejor rendimiento.

Consideraciones y Mejores Prácticas 🧠

  • Usa genéricos cuando realmente necesites la flexibilidad. No los añadas solo porque sí.
  • Las restricciones de tipo pueden hacer tu código más claro y seguro.
  • Los genéricos pueden hacer que el código sea más difícil de leer si se abusa de ellos. Úsalos con moderación.

Conclusión 🎉

Los genéricos en Go abren un mundo de posibilidades para escribir código más flexible y reutilizable. Aunque pueden parecer complicados al principio, con práctica se convierten en una herramienta poderosa en tu caja de herramientas de Go.

¿Ya estás usando genéricos en tus proyectos? ¿Tienes alguna idea genial para usarlos? ¡Comparte tus pensamientos y experiencias en los comentarios!

Recuerda, la clave está en encontrar el equilibrio entre la flexibilidad de los genéricos y la simplicidad que hace que Go sea tan querido. ¡Feliz coding, Gophers!

Comentarios

Formulario de contacto

Enviar