Genericos en Go
Tags: go, programming, beginners
Published: 2023-03-14 01:26:05

## Introducción
Go ha ido evolucionando a través de los años, incluyendo herramientas interesantes en las últimas versiones. Una de estas herramientas son los genéricos, algo que ya existía en otros lenguajes de programación, pero no en Golang, y que es algo que podemos explotar para nuestro beneficio.

## ¿Qué son los genéricos?
Los genéricos permiten que nuestras funciones o estructuras de datos puedan ser creadas de diferentes tipos, que se definen en su forma genérica.

## Ejemplo simple en java
En java, podemos tener como ejemplo los Arrays del paquete Utils:

```java
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Bag<Apple> applesBag = new Bag<>();
        applesBag.add(new Apple());
        applesBag.add(new Apple());
        applesBag.add(new Apple());
        System.out.println("Quantity of apples: " + applesBag.elementsQuantity());
        Bag<Orange> orangesBag = new Bag<>();
        orangesBag.add(new Orange());
        System.out.println("Quantity of oranges: " + applesBag.elementsQuantity());

    }

    static class Bag<K> {
        // Aca definimos una lista de K que estará en nuestra bolsa
        final List<K> listOfElements;

        public Bag(){
            listOfElements = new ArrayList<>();
        }

        public void add(K element) {
            listOfElements.add(element);
        }

        public int elementsQuantity(){
            return listOfElements.size();
        }
    }

    static class Apple {}
    static class Orange{}
}
```
En nuestro ejemplo en java creamos una bolsa personalizada, en donde podemos poner lo que queramos del tipo K, en este caso nuestro K puede ser tanto Apple como Orange.

## ¿Se podía hacer antes?
En golang solo los tipos nativos como map, slices y punteros entre otros podian ser genéricos, por lo que podiamos crear por ejemplo un `map[string]int` o un `[]int`, la forma de hacerlo antes, era crear un tipo para cada estructura:

```golang
package main

import "fmt"

func main() {
	applesBag := new(ApplesBag)
	applesBag.add(Apple{})
	applesBag.add(Apple{})
	applesBag.add(Apple{})
	fmt.Printf("Quantity of apples: %d\n", applesBag.elementsQuantity())
	orangesBag := new(OrangesBag)
	orangesBag.add(Orange{})
	fmt.Printf("Quantity of oranges: %d\n", orangesBag.elementsQuantity())
}

type ApplesBag struct {
	apples []Apple
}
type Apple struct{}

func (bag *ApplesBag) add(apple Apple) {
	bag.apples = append(bag.apples, apple)
}

func (bag *ApplesBag) elementsQuantity() int {
	return len(bag.apples)
}

type OrangesBag struct {
	oranges []Orange
}
type Orange struct{}

func (bag *OrangesBag) add(apple Orange) {
	bag.oranges = append(bag.oranges, apple)
}

func (bag *OrangesBag) elementsQuantity() int {
	return len(bag.oranges)
}
```
De esta forma vemos como tenemos que crear un Bag para cada elemento, repitiendo código por cada tipo diferente que hagamos.

## Como se hace ahora
Con la modificación que nos brinda la nueva SDK de Go, podemos hacer esto de una forma sencilla:
```golang
package main

import "fmt"

func main() {
	applesBag := Bag[Apple]{}
	applesBag.add(Apple{})
	applesBag.add(Apple{})
	applesBag.add(Apple{})
	fmt.Printf("Quantity of apples: %d\n", applesBag.elementsQuantity())
	orangesBag := Bag[Orange]{}
	orangesBag.add(Orange{})
	fmt.Printf("Quantity of oranges: %d\n", orangesBag.elementsQuantity())
}

// Tenemos una sola estructura Bag del tipo K
type Bag[K any] struct {
        // Que solo guarda objetos del tipo K
	objects []K
}

func (bag *Bag[K]) add(obj K) {
	bag.objects = append(bag.objects, obj)
}

func (bag *Bag[K]) elementsQuantity() int {
	return len(bag.objects)
}

type Orange struct{}
type Apple struct{}
```
De esta manera, el día de mañana nuestro código queda lo suficientemente desacoplado para crear objetos e instancias de Bag, y no tener que crear un objeto y un bag para cada tipo.
 
## Conclusión
Si en algún momento nos vimos con la necesidad de tomar este approach de Golang y no contábamos con esta solución, ahora vemos que llegó y podemos aprovecharla. Seguramente con el transcurso del tiempo empiezan a llegar nuevas herramientas igual de interesantes y útiles, seguimos a la espera de facilidades como las de manejar errores y otras cosillas más.