Novedades en Go 1.21 🚀
Tags: go, programming
Published: 2023-08-17 04:53:27

## Introducción
Después de la versión 1.20, Go lanza la versión 1.21 con algunas pequeñas novedades para explotar un poco más el lenguaje, como siempre la nueva versión tiene retrocompatibilidad con versiones anteriores, por lo que cambiar a la nueva versión no debería impactar en lo que ya tengamos hecho. Sin más vamos a revisar cuales son las novedades en esta versión:

## Cambios en el lenguaje

### Min y Max
En esta nueva versión de Go encontramos funciones nuevas integradas como min y max, el cual toma un listado de valores y los compara devolviendo mínimo o máximo respectivamente.

```go
package main

import "fmt"

func main() {
	x := 10
	y := 15
	mn := min(x, y) // m is the smaller of x and y
	fmt.Printf("The min is %d \n", mn)
	mx := max(x, y, 10) // m is the larger of x and y but at least 10
	fmt.Printf("The max is %d \n", mx)
	c := max(1, 2.0, 10) // c == 10.0 (floating-point kind)
	fmt.Printf("The max is %f \n", c)
	f := max(0, float32(x)) // type of f is float32
	fmt.Printf("The max is %f \n", f)
	// var s []string
	// _ = min(s...)// invalid: slice arguments are not permitted
	t := max("", "foo", "bar") // t == "foo" (string kind)
	fmt.Printf("The max is %s \n", t)
}
```

### Clear
Otra novedad de la nueva versión de Go, es la función `clear`
```go
package main

import "fmt"

func main() {
	var mapToClear = map[string]int{"k1": 1, "k2": 2, "k3": 3}
	clear(mapToClear) // Elimina todos los pares Key-Value (len(m) == 0)
	fmt.Printf("%v \n", mapToClear)
	var arr = []int{1, 2, 3, 4}
	clear(arr) // Vuelve todos los elementos al valor Zero del tipo
	fmt.Printf("%v \n", arr)
	/*
		var t = struct {
			// Name       string // Dato invalido para limpiar
			mapToClear map[string]int
		}{
			// Name:       "test",
			mapToClear: map[string]int{"k1": 1, "k2": 2, "k3": 3},
		}
		 clear(t) // No se puede hacer esto, tira un error ya que t debe ser del tipo map o slice
	*/
}

```

### Otras cositas del lenguaje
En cuanto a los **genéricos**, se hicieron mejoras en cuanto a la inferencia de los tipos. Ahora se incluye una explicación sobre el proceso y como funciona en la documentación oficial.

Algo que planean hacer, que esta incluido en la version 1.21 de Go como `experimental`, es arreglar la captura de variables en los ciclos `for`, para eso recomiendan ir al caso escrito en [LoopvarExperiment](https://github.com/golang/go/wiki/LoopvarExperiment)

## Novedades de la SDK

### Paquete log/slog
una de las cositas más interesantes que sumó esta nueva versión es el nuevo paquete [log/slog](https://pkg.go.dev/log/slog) para logging, el cual agrega funcionalidades a nuestro logging sin necesidad de sumar una librería:
```go
package main

import (
	"log"
	"log/slog"
)

func main() {
	slog.Info("hello", "count", 3)
	// 2009/11/10 23:00:00 INFO hello count=3
	log.Println("hello", "count", 3)
	// 2009/11/10 23:00:00 hello count 3

	slog.Info("hello", "count", 1)
	// 2009/11/10 23:00:00 INFO hello count=1
	slog.Error("hello", "count", 2)
	// 2009/11/10 23:00:00 ERROR hello count=2
	slog.Warn("hello", "count", 3)
	// 2009/11/10 23:00:00 WARN hello count=3
	slog.Debug("hello", "count", 4)
	// 2009/11/10 23:00:00 DEBUG hello count=4

	// Print as json
	h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
	slog.SetDefault(slog.New(h))
	slog.Debug("it's a debug log")
}
```

### Paquete slice
Nuevo paquete [slice](https://pkg.go.dev/slices) para manejo de slices justamente, esta incluye funcionalidades interesantes como métodos de ordenamiento o de búsquedas:
```go
package main

import (
	"fmt"
	"slices"
)

func main() {
	arr := []int{8, 2, 4, 5, 1}
	slices.Sort(arr) // Es mutable, por lo que cambia el array original
	fmt.Println(arr) // [1 2 4 5 8]

	index, found := slices.BinarySearch(arr, 2)
	fmt.Println(found, index) // true 1
}
```

### Paquete  maps
Tambien se suma un nuevo paquete [maps](https://pkg.go.dev/maps) para los mapas pero con menos funciones:
```go
package main

import (
	"fmt"
	"maps"
)

func main() {
	mapEx := map[string]int{"k1": 1, "k2": 2}
	mapClone := maps.Clone(mapEx)
	fmt.Println(mapClone) // map[k1:1 k2:2]

	equal := maps.Equal(mapEx, mapClone)
	fmt.Println(equal) // true
}
```

### Paquete cmp
Tambien se agrega un nuevo paquete [cmp](https://pkg.go.dev/cmp) para comparar elementos:
```go
package main

import (
	"cmp"
	"fmt"
)

func main() {
	// -1 if x is less than y,
	// 0 if x equals y,
	// +1 if x is greater than y.
	x := 5
	y := 10
	res := cmp.Compare(x, y)
	fmt.Println(res) // -1
	res = cmp.Compare(y, x)
	fmt.Println(res) // 1
	res = cmp.Compare(5, x)
	fmt.Println(res) // 0

	isLess := cmp.Less(5, x)
	fmt.Println(isLess) // false
	isLess = cmp.Less(x, y)
	fmt.Println(isLess) // true
}
```
## Profile Guided Optimization
La herramienta [Profile Guided Optimization (PGO)](https://go.dev/doc/pgo) anunciada en la versión 1.20 ahora está disponible sin necesidad de habilitarla. Con esta herramienta vamos a poder construir paquetes más optimizados. Incluso se ha medido el impacto en varios programas y se ve mejoras del 2% al 7%.

## Mejoras en la performance
Además de lo mencionado en PGO, podemos ver:
* El compilador de go fue reconstruido en la nueva versión con PGO habilitado, lo que logró hacerlo 2-4% más rápido dependiendo del sistema que lo ejecute.
* Debido a la mejora en el Garbage Collector, se detecta una reducción del 40% en la latencia de cola.
* Ahora la recolección de runtime/trace ahora reduce el costo para arquitectura arm64 y amd64.

## Conclusión
Estas son algunas de las novedades que podemos detectar de la nueva versión de go, para más detalle puede ir a leer el blog oficial en https://go.dev/blog/go1.21. Espero les ayude este resumen a poder comprenderlo.