Cómo crear y usar maps en Go: make, ok‑pattern y recorridos paso a paso
Introducción
Los maps son una de las estructuras de datos más usadas en Go. Son la forma nativa de trabajar con colecciones de pares clave‑valor, similar a los objetos en JavaScript o los diccionarios en Python. En este artículo vas a aprender a:
- Crear un map desde cero usando la función
make. - Verificar la existencia de una clave mediante el ok‑pattern.
- Recorrer el map con los bucles
for rangey obtener tanto claves como valores.
El contenido está pensado para desarrolladores que ya conocen la sintaxis básica de Go y quieren dominar el manejo de maps de manera segura y eficiente. Cada sección incluye ejemplos completos, la salida esperada y buenas prácticas para evitar errores comunes.
1. Creación de maps con make
1.1 ¿Por qué usar make?
En Go, los maps pueden declararse de dos formas:
var m map[string]int // mapa nil, no tiene memoria asignada
m = make(map[string]int) // mapa vacío, listo para usarSi intentás escribir en un map declarado pero sin inicializar (nil), el programa panics con assignment to entry in nil map. Por eso la forma recomendada es usar make, que asigna la estructura interna y permite insertar elementos inmediatamente.
1.2 Sintaxis básica
// Crear un map que asocie nombres de usuarios con su edad
ages := make(map[string]int)
// Insertar algunos valores
ages["juan"] = 28
ages["maria"] = 31
ages["pedro"] = 22
fmt.Println(ages)Salida esperada
map[juan:28 maria:31 pedro:22]1.3 Map con capacidad predefinida
make también permite indicar una capacidad inicial. Esto es útil cuando ya sabés cuántos elementos vas a almacenar, ya que reduce la cantidad de realocaciones internas.
// Creamos un map con capacidad para 5 elementos
scores := make(map[string]float64, 5)
scores["alice"] = 9.5
scores["bob"] = 8.0
fmt.Printf("len=%d cap=%d
", len(scores), cap(scores))Salida esperada
len=2 cap=5Nota: La capacidad (
cap) solo tiene efecto en la fase de crecimiento; Go sigue gestionando la memoria automáticamente.
2. Verificación de claves con el ok‑pattern
2.1 El problema de acceder a una clave inexistente
Cuando leemos value := myMap[key] y la clave no está presente, Go devuelve el valor cero del tipo del map. Esto puede llevar a confusiones si el valor cero es un dato válido.
m := make(map[string]int)
m["x"] = 0
v := m["y"] // clave inexistente
fmt.Println(v) // imprime 0, pero ¿existe realmente?2.2 La solución: el segundo valor retornado
Go permite obtener dos valores al acceder a un map:
value, ok := m[key]valuees el valor asociado (o cero si no existe).okes un boolean que indica si la clave estaba presente.
Ejemplo completo
stock := map[string]int{"manzanas": 12, "peras": 5}
if qty, ok := stock["naranjas"]; ok {
fmt.Printf("Hay %d naranjas en stock.
", qty)
} else {
fmt.Println("No hay naranjas en stock.")
}Salida esperada
No hay naranjas en stock.2.3 Uso del ok‑pattern para actualizar valores
Muchas veces necesitás incrementar un contador o acumular datos. Con el ok‑pattern podés hacerlo de forma segura:
visits := make(map[string]int)
func registrarVisita(usuario string) {
if cnt, ok := visits[usuario]; ok {
visits[usuario] = cnt + 1
} else {
visits[usuario] = 1
}
}
registrarVisita("alice")
registrarVisita("bob")
registrarVisita("alice")
fmt.Println(visits)Salida esperada
map[alice:2 bob:1]3. Iteración sobre maps
3.1 for range básico
El bucle for range es la forma idiomática de recorrer un map. En cada iteración devuelve la clave y el valor.
prices := map[string]float64{"café": 1.5, "té": 1.2, "azúcar": 0.8}
for product, price := range prices {
fmt.Printf("%s cuesta %.2f USD
", product, price)
}Salida esperada (el orden es aleatorio)
café cuesta 1.50 USD
azúcar cuesta 0.80 USD
té cuesta 1.20 USDImportante: El orden de iteración no está garantizado. Si necesitás un orden específico, tenés que extraer las claves, ordenarlas y luego acceder a los valores.
3.2 Recorrer solo claves o solo valores
A veces solo te interesa una de las dos partes. Puedes ignorar la que no necesites usando el guion bajo _.
// Solo claves
for key := range prices {
fmt.Println("producto:", key)
}
// Solo valores
for _, value := range prices {
fmt.Printf("precio: %.2f
", value)
}3.3 Iterar mientras modificás el map
Go permite añadir o eliminar elementos del map durante la iteración, pero hay que hacerlo con cuidado porque la especificación no garantiza el comportamiento en todas las implementaciones. La práctica más segura es recopilar los cambios y aplicarlos después del bucle.
// Ejemplo seguro: eliminar entradas con valor 0
data := map[string]int{"a": 1, "b": 0, "c": 3}
toDelete := []string{}
for k, v := range data {
if v == 0 {
toDelete = append(toDelete, k)
}
}
for _, k := range toDelete {
delete(data, k)
}
fmt.Println(data)Salida esperada
map[a:1 c:3]4. Buenas prácticas y errores comunes
| Buenas prácticas | Por qué son útiles |
|---|---|
Siempre usar make antes de insertar valores |
Evita panics por map nil. |
| Utilizar el ok‑pattern al leer | Diferencia entre "valor cero" y "clave inexistente". |
| No confiar en el orden de iteración | Go no garantiza orden; si lo necesitás, ordená las claves. |
Prefiere tipos concretos (ej. map[string]int en vez de map[interface{}]interface{}) |
Mejora la legibilidad y el rendimiento del compilador. |
| Limitar la capacidad a un estimado razonable | Reduce re‑allocations y mejora la eficiencia de memoria. |
Errores frecuentes
Olvidar inicializar el map
var m map[string]int m["x"] = 1 // panic!Solución:
m := make(map[string]int).Sobreescribir valores sin querer
m := map[string]int{"a": 1} m["a"] = 2 // se pierde el 1Tip: Usa una función de actualización que sume o combine valores.
Asumir que
len(m)es constante durante la iteración
El tamaño del map puede cambiar si lo modificás dentro delfor range. Recolectá cambios y aplícalos después.
5. Conclusión
En este artículo aprendiste a crear maps con make, a **verificar la existencia de claves usando el ok‑pattern y a recorrerlos de forma segura y eficiente. Recordá siempre inicializar tus maps, usar el segundo valor retornado para distinguir entre "clave no encontrada" y "valor cero", y no confiar en el orden de los elementos.
Con estos conceptos bajo la manga, podés construir desde simples tablas de conteo hasta estructuras más complejas como índices en memoria o cachés de resultados. Como próximo paso, experimentá con maps anidados (map[string]map[int]bool) y explora la concurrencia usando sync.Map cuando necesites acceso seguro desde múltiples gorutinas.
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.