← Go EspañolChapter 07 of 13

Maps

## Objetivos de Aprendizaje - Comprender los maps de Go (tablas hash) - Crear e inicializar maps - Añadir, acceder y eliminar entradas - Iterar sobre maps - Manejar claves faltantes de forma segura ## ¿Qué es un Map? Un map es una implementación de tabla hash - una colección no ordenada de pares clave-valor donde las claves son únicas. ## Declaración ### Con make ```go ages := make(map[string]int) ages["Alice"] = 30 ages["Bob"] = 25 ``` ### Con Literales ```go ages := map[string]int{ "Alice": 30, "Bob": 25, "Carol": 35, } ``` ### Map Nil ```go var ages map[string]int // map nil (no se puede añadir a él) ages = make(map[string]int) // Inicializar antes de usar ``` ## Operaciones Básicas ### Añadir/Actualizar ```go ages := make(map[string]int) ages["Alice"] = 30 // Añadir ages["Alice"] = 31 // Actualizar ``` ### Acceder ```go ages := map[string]int{ "Alice": 30, "Bob": 25, } fmt.Println(ages["Alice"]) // 30 fmt.Println(ages["Unknown"]) // 0 (valor cero) ``` ### Verificar Existencia de Clave ```go ages := map[string]int{ "Alice": 30, } value, exists := ages["Alice"] fmt.Println(value, exists) // 30 true value, exists = ages["Bob"] fmt.Println(value, exists) // 0 false ``` ### Eliminar ```go ages := map[string]int{ "Alice": 30, "Bob": 25, } delete(ages, "Bob") fmt.Println(ages) // map[Alice:30] ``` ### Eliminar Clave No Existente ```go ages := map[string]int{"Alice": 30} delete(ages, "Bob") // Seguro - sin error aunque la clave no exista ``` ## Longitud ```go ages := map[string]int{ "Alice": 30, "Bob": 25, } fmt.Println(len(ages)) // 2 ``` ## Iteración ### Iteración Básica ```go ages := map[string]int{ "Alice": 30, "Bob": 25, "Carol": 35, } for key, value := range ages { fmt.Printf("%s: %d\n", key, value) } ``` ### Orden - El orden de iteración de un map **no está garantizado** - El orden puede diferir entre iteraciones ### Solo Clave ```go for key := range ages { fmt.Println(key) } ``` ### Claves Ordenadas ```go ages := map[string]int{ "Charlie": 35, "Alice": 30, "Bob": 25, } keys := make([]string, 0, len(ages)) for key := range ages { keys = append(keys, key) } sort.Strings(keys) for _, key := range keys { fmt.Printf("%s: %d\n", key, ages[key]) } ``` ## Valor Cero ### Leer de un Map Nil ```go var ages map[string]int // nil fmt.Println(ages["Alice"]) // 0 fmt.Println(len(ages)) // 0 delete(ages, "Alice") // Seguro // ages["Alice"] = 30 // ¡PANIC! ``` ### Verificar Antes de Escribir ```go var ages map[string]int if ages == nil { ages = make(map[string]int) } ages["Alice"] = 30 // Ahora es seguro ``` ## Map como Referencia Los maps son tipos de referencia - copiar un map comparte los datos subyacentes. ```go ages1 := map[string]int{"Alice": 30} ages2 := ages1 ages2["Alice"] = 31 fmt.Println(ages1["Alice"]) // 31 (ambos referencian el mismo map) fmt.Println(ages2["Alice"]) // 31 ``` ## Punteros a Maps ```go func modify(m map[string]int) { m["Alice"] = 31 } ages := map[string]int{"Alice": 30} modify(ages) fmt.Println(ages["Alice"]) // 31 ``` ## Patrones Comunes ### Conteo de Palabras ```go text := "hello world hello go programming hello" words := strings.Fields(text) count := make(map[string]int) for _, word := range words { count[word]++ } fmt.Println(count) // map[hello:3 world:1 go:1 programming:1] ``` ### Implementación de Set ```go type Set struct { items map[string]struct{} } func NewSet() *Set { return &Set{make(map[string]struct{})} } func (s *Set) Add(item string) { s.items[item] = struct{}{} } func (s *Set) Contains(item string) bool { _, exists := s.items[item] return exists } func (s *Set) Remove(item string) { delete(s.items, item) } func main() { set := NewSet() set.Add("apple") set.Add("banana") fmt.Println(set.Contains("apple")) // true fmt.Println(set.Contains("orange")) // false } ``` ### Agrupar Por ```go people := []struct { Name string Age int }{ {"Alice", 30}, {"Bob", 25}, {"Carol", 30}, {"David", 25}, } groups := make(map[int][]string) for _, p := range people { groups[p.Age] = append(groups[p.Age], p.Name) } fmt.Println(groups) // map[25:[Bob David] 30:[Alice Carol]] ``` ### Valores Únicos ```go func unique(ints []int) []int { seen := make(map[int]bool) result := []int{} for _, n := range ints { if !seen[n] { seen[n] = true result = append(result, n) } } return result } ``` ## Comparación ### Los Maps No Pueden Ser Comparados ```go m1 := map[string]int{"a": 1} m2 := map[string]int{"a": 1} // m1 == m2 // ERROR DE COMPILACIÓN: map solo puede compararse con nil ``` ### Comparación Profunda ```go func equalMaps(m1, m2 map[string]int) bool { if len(m1) != len(m2) { return false } for k, v1 := range m1 { if v2, ok := m2[k]; !ok || v1 != v2 { return false } } return true } ``` ## Acceso Concurrente ### Condición de Carrera Los maps no son seguros para acceso concurrente por defecto. ```go var counter = make(map[string]int) // ¡Esto es inseguro! go func() { for i := 0; i < 1000; i++ { counter["a"]++ } }() go func() { for i := 0; i < 1000; i++ { counter["a"]++ } }() ``` ### sync.RWMutex ```go import "sync" var counter = struct { sync.RWMutex m map[string]int }{m: make(map[string]int)} counter.Lock() counter.m["a"]++ counter.Unlock() counter.RLock() fmt.Println(counter.m["a"]) counter.RUnlock() ``` ### sync.Map ```go var syncMap sync.Map syncMap.Store("a", 1) value, ok := syncMap.Load("a") syncMap.Delete("a") syncMap.Range(func(key, value interface{}) bool { fmt.Printf("%s: %d\n", key, value) return true }) ``` ## Resumen - Los maps son tablas hash - pares clave-valor con claves únicas - Crear con `make()` o literales de map - El valor cero es `nil` - no se puede añadir a un map nil - Leer clave no existente retorna valor cero - Usar el idiom comma-ok para verificar existencia de clave - `delete()` es seguro incluso si la clave no existe - El orden de iteración no está garantizado - Los maps son tipos de referencia - No son seguros para acceso concurrente - usar sync.RWMutex o sync.Map

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →