Map

Map

Imagine consultar um dicionário: você insere uma palavra (chave) e pode encontrar imediatamente sua definição (valor). Você não precisa folhear da primeira à última página — vai diretamente à página alvo. O map do Go é exatamente esse "dicionário" — é uma estrutura de dados chave-valor que permite buscar rapidamente um valor por chave com complexidade de tempo O(1).


1. Conceitos Fundamentais

Conceito Descrição
Definição map[KeyType]ValueType; KeyType deve ser um tipo comparável (não pode ser slice, map, func)
Criação make(map[K]V) ou literal map[K]V{}
Adicionar/Atualizar m[chave] = valor (adiciona se a chave não existe, sobrescreve se existe)
Ler v := m[chave]
Deletar delete(m, chave)
Padrão comma ok v, ok := m[chave]; ok é falso quando a chave não existe
Iteração for k, v := range m (ordem aleatória, não confiável)
Comprimento len(m)
⚠️ Nota: map é um tipo de referência; atribuição e passagem de parâmetros passam a referência, não uma cópia dos dados.


2. Sintaxe/Uso Básico

Criando um Map

GO
// Método 1: Usando make
m1 := make(map[string]int)

// Método 2: Criação literal com inicialização
m2 := map[string]int{
    "maca":   5,
    "banana": 3,
}

// Método 3: Declarar e depois atribuir
var m3 map[string]int        // m3 é nil aqui, não pode atribuir diretamente
m3 = make(map[string]int)    // Inicializar primeiro
m3["cereja"] = 7             // Depois atribuir
💡 Dica: Um map declarado com var m map[K]V é nilescrever nele causará panic, mas ler dele (retorna valor zero) e len() (retorna 0) funcionam normalmente.

Operações CRUD

GO
m := map[string]int{"a": 1, "b": 2}

// Criar
m["c"] = 3

// Atualizar
m["a"] = 10

// Ler
v := m["a"]  // v = 10

// Deletar
delete(m, "b")
💡 Dica: Deletar uma chave inexistente não causará erro; nada acontece.

Padrão Comma Ok

GO
m := map[string]int{"x": 42}

v, ok := m["x"]  // v = 42, ok = true
v, ok = m["y"]   // v = 0, ok = false (retorna o valor zero de int)

if _, existe := m["z"]; !existe {
    fmt.Println("chave 'z' não existe")
}
💡 Dica: Se você não se importa com o valor, use _ para ignorá-lo: _, ok := m[chave].


3. Código de Exemplo

Exemplo 1: Uso Básico (Dificuldade ⭐)

Crie uma tabela de notas de estudantes e realize operações CRUD.

GO
package main

import "fmt"

func main() {
    // Criar map de notas dos estudantes
    notas := map[string]int{
        "Alice": 90,
        "Bob":   85,
    }

    // Adicionar um estudante
    notas["Charlie"] = 92

    // Modificar nota do Bob
    notas["Bob"] = 88

    // Consultar nota da Alice
    fmt.Println("Nota da Alice:", notas["Alice"])

    // Deletar Charlie
    delete(notas, "Charlie")

    // Iterar todas as notas dos estudantes
    for nome, nota := range notas {
        fmt.Printf("%s: %d\n", nome, nota)
    }

    fmt.Println("Número de estudantes:", len(notas))
}
▶ Experimente

Exemplo de saída (a ordem de iteração pode variar):

TEXT
Nota da Alice: 90
Bob: 88
Alice: 90
Número de estudantes: 2

Exemplo 2: Uso Intermediário (Dificuldade ⭐⭐)

Consulta segura com padrão comma ok, iteração de maps e maps aninhados.

GO
package main

import "fmt"

func main() {
    // ========== Padrão comma ok ==========
    frutas := map[string]int{
        "maca":   5,
        "banana": 3,
    }

    // Consulta segura
    if quantidade, ok := frutas["maca"]; ok {
        fmt.Printf("maca tem %d\n", quantidade)
    }

    if quantidade, ok := frutas["uva"]; !ok {
        fmt.Println("uva não existe, adicionando à lista")
        frutas["uva"] = 10
    }

    // ========== Iteração com range ==========
    fmt.Println("\nTodas as frutas:")
    for fruta, quantidade := range frutas {
        fmt.Printf("  %s: %d\n", fruta, quantidade)
    }

    // ========== Map aninhado (map de maps) ==========
    // Turma -> Estudante -> Nota
    notasTurma := map[string]map[string]int{
        "Turma A": {
            "Alice": 90,
            "Bob":   85,
        },
        "Turma B": {
            "Charlie": 92,
            "Diana":   88,
        },
    }

    // Consultar map aninhado
    if turma, ok := notasTurma["Turma A"]; ok {
        if nota, ok := turma["Alice"]; ok {
            fmt.Printf("\nNota da Alice na Turma A: %d\n", nota)
        }
    }

    // Iterar map aninhado
    fmt.Println("\nNotas de todas as turmas:")
    for turma, estudantes := range notasTurma {
        fmt.Printf("  %s:\n", turma)
        for nome, nota := range estudantes {
            fmt.Printf("    %s: %d\n", nome, nota)
        }
    }
}
▶ Experimente

Saída:

TEXT
maca tem 5
uva não existe, adicionando à lista

Todas as frutas:
  maca: 5
  banana: 3
  uva: 10

Nota da Alice na Turma A: 90

Notas de todas as turmas:
  Turma A:
    Alice: 90
    Bob: 85
  Turma B:
    Charlie: 92
    Diana: 88

Exemplo 3: Aplicação Abrangente (Dificuldade ⭐⭐⭐)

Implemente um contador de frequência de palavras com processamento de dados baseado em map (saída ordenada, encontrar palavras de alta frequência).

GO
package main

import (
    "fmt"
    "sort"
    "strings"
)

// WordCounter conta ocorrências de cada palavra em um texto
func WordCounter(texto string) map[string]int {
    // Converter para minúsculas e dividir por espaços em branco
    palavras := strings.Fields(strings.ToLower(texto))

    // Criar map de frequência de palavras
    freq := make(map[string]int)

    for _, palavra := range palavras {
        // Remover pontuação (processamento simples)
        palavra = strings.Trim(palavra, ".,!?;:\"'")
        if palavra != "" {
            freq[palavra]++
        }
    }

    return freq
}

// TopN retorna as N palavras mais frequentes (ordem decrescente de frequência)
func TopN(freq map[string]int, n int) []string {
    // Converter map para slice ordenável
    type wordFreq struct {
        word  string
        count int
    }

    // Construir slice
    pares := make([]wordFreq, 0, len(freq))
    for w, c := range freq {
        pares = append(pares, wordFreq{w, c})
    }

    // Ordenar por frequência decrescente
    sort.Slice(pares, func(i, j int) bool {
        if pares[i].count == pares[j].count {
            return pares[i].word < pares[j].word // Alfabético quando frequência é igual
        }
        return pares[i].count > pares[j].count
    })

    // Pegar top N
    if n > len(pares) {
        n = len(pares)
    }

    resultado := make([]string, n)
    for i := 0; i < n; i++ {
        resultado[i] = fmt.Sprintf("%s(%d)", pares[i].word, pares[i].count)
    }

    return resultado
}

// MergeFreq mescla dois maps de frequência de palavras
func MergeFreq(a, b map[string]int) map[string]int {
    resultado := make(map[string]int)

    // Copiar dados de a
    for k, v := range a {
        resultado[k] = v
    }

    // Acumular dados de b
    for k, v := range b {
        resultado[k] += v
    }

    return resultado
}

func main() {
    texto1 := "Go é ótimo. Go é rápido. Go é fácil de aprender."
    texto2 := "Eu amo Go. Go torna a programação divertida e fácil."

    // Contar frequência de palavras
    freq1 := WordCounter(texto1)
    freq2 := WordCounter(texto2)

    fmt.Println("Frequência de palavras do Texto 1:")
    for palavra, count := range freq1 {
        fmt.Printf("  %s: %d\n", palavra, count)
    }

    fmt.Println("\nFrequência de palavras do Texto 2:")
    for palavra, count := range freq2 {
        fmt.Printf("  %s: %d\n", palavra, count)
    }

    // Mesclar frequências de palavras
    merged := MergeFreq(freq1, freq2)

    // Encontrar as 5 palavras mais frequentes
    fmt.Println("\nTop 5 palavras de alta frequência após mesclagem:")
    top5 := TopN(merged, 5)
    for i, item := range top5 {
        fmt.Printf("  %d. %s\n", i+1, item)
    }

    // Contar total de palavras
    totalPalavras := 0
    for _, count := range merged {
        totalPalavras += count
    }
    fmt.Printf("\nTotal de palavras: %d, Palavras únicas: %d\n", totalPalavras, len(merged))
}
▶ Experimente

Exemplo de saída:

TEXT
Frequência de palavras do Texto 1:
  go: 3
  é: 3
  ótimo: 1
  rápido: 1
  fácil: 1
  de: 1
  aprender: 1

Frequência de palavras do Texto 2:
  eu: 1
  amo: 1
  go: 2
  torna: 1
  a: 1
  programação: 1
  divertida: 1
  e: 1
  fácil: 1

Top 5 palavras de alta frequência após mesclagem:
  1. go(5)
  2. é(3)
  3. fácil(2)
  4. a(1)
  5. amo(1)

Total de palavras: 18, Palavras únicas: 13

3. Casos de Uso Comuns

Caso 1: Cache / Busca Rápida

Use um map para implementar um cache simples em memória para evitar computação redundante.

GO
package main

import "fmt"

// Sequência de Fibonacci (com cache)
var cache = map[int]int{0: 0, 1: 1}

func fib(n int) int {
    // Verificar cache primeiro
    if val, ok := cache[n]; ok {
        return val
    }

    // Cache miss, computar e armazenar no cache
    resultado := fib(n-1) + fib(n-2)
    cache[n] = resultado
    return resultado
}

func main() {
    for i := 0; i <= 10; i++ {
        fmt.Printf("fib(%d) = %d\n", i, fib(i))
    }
    fmt.Println("\nConteúdo do cache:", cache)
}

Caso 2: Estatísticas de Agrupamento

Use um map para agrupar e contar dados.

GO
package main

import "fmt"

func main() {
    // Lista de estudantes: nome -> turma
    estudantes := map[string]string{
        "Alice":   "Turma A",
        "Bob":     "Turma B",
        "Charlie": "Turma A",
        "Diana":   "Turma B",
        "Eve":     "Turma A",
    }

    // Agrupar por turma
    grupos := make(map[string][]string)
    for nome, turma := range estudantes {
        grupos[turma] = append(grupos[turma], nome)
    }

    // Imprimir resultados agrupados
    for turma, membros := range grupos {
        fmt.Printf("%s (%d pessoas): %v\n", turma, len(membros), membros)
    }
}

Saída:

TEXT
Turma A (3 pessoas): [Alice Charlie Eve]
Turma B (2 pessoas): [Bob Diana]

❓ Perguntas Frequentes

P1: Por que a ordem de iteração de um map é diferente a cada vez?

Go intencionalmente randomiza a ordem de iteração do map. Isso impede que desenvolvedores dependam da ordem de iteração do map, já que a estrutura interna pode mudar em cenários concorrentes. Se precisar de iteração ordenada, colete as chaves em um slice primeiro, ordene-as e depois itere:

GO
chaves := make([]string, 0, len(m))
for k := range m {
    chaves = append(chaves, k)
}
sort.Strings(chaves)
for _, k := range chaves {
    fmt.Println(k, m[k])
}

P2: Um map é thread-safe?

Não. O map do Go não é seguro para concorrência; múltiplas goroutines lendo e escrevendo no mesmo map simultaneamente causarão um panic. Soluções:

GO
// Usando sync.Map
var m sync.Map
m.Store("chave", "valor")
v, ok := m.Load("chave")

P3: Quais tipos podem ser usados como chaves de map?

Chaves de map devem ser tipos comparáveis, incluindo:

Tipos que não podem ser chaves: slice, map, func.

P4: Como verificar se um map contém determinada chave?

Use o padrão comma ok:

GO
if _, ok := m[chave]; ok {
    // Chave existe
} else {
    // Chave não existe
}

Não verifique se uma chave existe testando se o valor é um valor zero, pois o valor zero pode ser um valor válido.


📖 Resumo


📝 Exercícios

Exercício 1 (⭐)

Crie um map armazenando 5 linguagens de programação e seus anos de invenção, depois:

  1. Adicione 2 novas linguagens
  2. Modifique o ano de uma linguagem
  3. Delete uma linguagem
  4. Use o padrão comma ok para verificar se uma linguagem existe
  5. Itere e imprima todo o conteúdo

Exercício 2 (⭐⭐)

Implemente um programa simples de contatos:

  1. Defina map[string][]string, onde a chave é o nome do contato e o valor é a lista de números de telefone
  2. Implemente funções: adicionar contato, adicionar número de telefone, buscar contato, deletar contato
  3. Implemente a exibição de todos os contatos agrupados pela primeira letra
GO
// Exemplo de saída esperada:
// A: Alice - [13800001111, 13900002222]
// B: Bob - [13700003333]

Exercício 3 (⭐⭐⭐)

Implemente um sistema de gerenciamento de notas de estudantes:

  1. Use map aninhado map[string]map[string]float64 (turma -> estudante -> nota)
  2. Implemente funções: adicionar nota, consultar todas as notas de disciplinas de um estudante, calcular média da turma
  3. Implemente função: encontrar o estudante com a nota mais alta em cada disciplina em todas as turmas
  4. Saída dos resultados como tabelas formatadas
GO
// Exemplo de saída esperada:
// ========== Médias das Turmas ==========
// Turma A: 87.5
// Turma B: 91.2
//
// ========== Melhores Notas por Disciplina ==========
// Matemática: Alice (98.0)
// Inglês: Bob (95.0)

Próxima Lição

👉 07-struct - Structs

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%