Los maps en Go son tablas hash no ordenadas que asocian claves con valores. Son el tipo de colección clave-valor del lenguaje estándar y se usan ampliamente para contar, agrupar, cachear y representar datos estructurados cuando no se conoce el esquema en tiempo de compilación.
Crear un map
package main
import "fmt"
func main() {
// con make
edades := make(map[string]int)
edades["Ana"] = 30
edades["Luis"] = 25
// literal con valores iniciales
colores := map[string]string{
"rojo": "#FF0000",
"verde": "#00FF00",
"azul": "#0000FF",
}
fmt.Println(edades["Ana"]) // 30
fmt.Println(colores["verde"]) // #00FF00
}
Leer claves sin errores: el patrón ok
Leer una clave que no existe devuelve el zero value del tipo de valor, sin error ni pánico. Para saber si la clave existe, usa la forma de dos valores:
edad, ok := edades["Maria"]
if ok {
fmt.Println("María tiene", edad, "años")
} else {
fmt.Println("María no está en el map") // este caso
}
// También funciona en una sola línea:
if v, ok := colores["amarillo"]; ok {
fmt.Println("amarillo:", v)
}
Añadir, actualizar y eliminar
// añadir o actualizar edades["Carlos"] = 40 edades["Ana"] = 31 // sobreescribe el valor anterior // eliminar delete(edades, "Luis") // delete sobre clave inexistente no hace nada ni produce error delete(edades, "no_existe")
Iterar con range
El orden de iteración sobre un map es intencionalmente aleatorio en Go. No dependas del orden:
puntuaciones := map[string]int{
"Ana": 95,
"Luis": 87,
"Marta": 92,
}
for nombre, puntos := range puntuaciones {
fmt.Printf("%s: %dn", nombre, puntos)
}
// orden arbitrario en cada ejecución
Si necesitas orden, recoge las claves en un slice y ordénalo:
import "sort"
claves := make([]string, 0, len(puntuaciones))
for k := range puntuaciones {
claves = append(claves, k)
}
sort.Strings(claves)
for _, k := range claves {
fmt.Printf("%s: %dn", k, puntuaciones[k])
}
Map nil: el error que desconcierta a los principiantes
Un map declarado pero no inicializado es nil. Leer de un map nil es seguro (devuelve zero values), pero escribir en él produce un pánico:
var m map[string]int fmt.Println(m["clave"]) // 0 seguro leer m["clave"] = 1 // panic: assignment to entry in nil map
Inicializa siempre con make o un literal antes de escribir.
Maps y goroutines: problema de concurrencia
Los maps en Go no son seguros para escrituras concurrentes. Si dos goroutines escriben en el mismo map simultáneamente, el programa puede entrar en pánico o producir corrupción de datos. El detector de carreras lo detecta:
go run -race main.go # WARNING: DATA RACE # Write at 0x00c0000b8000 by goroutine 7
Para uso concurrente, usa sync.RWMutex o el tipo sync.Map de la biblioteca estándar.
Contar frecuencias: patrón típico
texto := "programacion en go y mas go y go"
palabras := strings.Fields(texto)
frecuencia := make(map[string]int)
for _, p := range palabras {
frecuencia[p]++ // zero value es 0, así que funciona desde el primer uso
}
fmt.Println(frecuencia["go"]) // 3
