Ma

Mapas en Go

2 ejercicios

Acerca de Mapas

En Go, map es un tipo de dato integrado que representa una tabla hash. En otros lenguajes de programación, quizás conozcas map como dict, como array asociativo o como almacén de clave/valor. Si no estás familiarizado con ese concepto, puedes pensar en map como un diccionario, donde cada palabra es la key y la definición es el element del map.

Antes de empezar, me gustaría señalarte la especificación de Go para map y el blog de Go sobre map para que profundices más en map.

Sintácticamente, map se ve así:

map[KeyType]ElementType

KeyType debe ser cualquier tipo comparable, mientras que ElementType puede ser cualquier tipo válido en Go, lo que significa que puedes almacenar desde una variable primitiva hasta un slice.

Es importante recordar que map en Go no tiene un orden definido; si intentas recorrer un map e imprimir el elemento, puede que te sorprendas al ver que tus elementos se imprimen en orden aleatorio (pruébalo si quieres).

También es importante saber que cada clave es única, lo que significa que asignar la misma clave dos veces sobrescribirá el valor de la clave correspondiente.

map es un tipo de referencia, lo que significa que si lo pasas de un lado a otro, Go no copiará el map completo. En su lugar, lo que Go hará es copiar el puntero del map, lo que hace que pasar un map a una función o variable sea barato. El valor de un map sin inicializar es nil.

Puedes definir un map de la siguiente manera (a esto también lo llamamos un nil map);

  var foo map[string]int

Para inicializar un map, puedes hacer:

  // With map literal
  foo := map[string]int{}

o

  // or with make function
  foo := make(map[string]int)

Un nil map es distinto de un map inicializado; escribir en un nil map provocará un error en tiempo de ejecución

panic: assignment to entry in nil map

Por lo tanto, es importante inicializar un map antes de usarlo

Estas son algunas operaciones que puedes hacer con un map

  // Add a value in a map with the `=` operator:
  foo["bar"] = 42
  // Here we update the element of `bar`
  foo["bar"] = 73
  // To retrieve a map value, you can use
  baz := foo["bar"]
  // To delete an item from a map, you can use
  delete(foo, "bar")

Si intentas obtener el valor de una clave que no existe en el map, se devolverá el valor cero del tipo del valor. Esto puede confundirte, sobre todo si el valor predeterminado de tu ElementType (por ejemplo, 0 para un int) es un valor válido. Para comprobar si una clave existe en tu map, puedes usar

  value, exists := foo["baz"]
  // If the key "baz" does not exist,
  // value: 0; exists: false

Como vimos antes, detectar si un map está inicializado o no es fácil: simplemente podemos compararlo con nil. Pero, ¿qué pasa con otros maps? Bueno, como map no es un tipo comparable, no podemos usar el operador ==, pero el paquete reflect tiene algo que nos puede rescatar: se llama DeepEqual y podemos usarlo así

import "reflect"

// ....

equal := reflect.DeepEqual(map[string]int{}, map[string]int{})
fmt.Println(equal)
// Output: true

Pero espera, si map no es comparable, ¿por qué podemos compararlo con nil? Bueno, la especificación hizo una excepción para esto; consulta la especificación de comparables

Por último, si intentas escribir en un map desde varias goroutines, eso activará el detector de carreras; consulta la documentación de Go y The Go Blog. Como alternativa, puedes usar sync.Map, atomic o mutex para sortear este problema.

Editar en GitHub El enlace se abre en una ventana o pestaña nueva

Aprende Mapas

La práctica está bloqueada

Desbloquea 3 ejercicios más para practicar Mapas