Pular para o conteúdo
•Leitura

Maps em Go: o guia completo

Maps em Go: o guia completo

Maps em Go são estruturas de dados que armazenam pares de chave e valor, permitindo acesso rápido aos dados através de uma chave única. Eles são essenciais para organizar informações de forma eficiente e aparecem em praticamente todos os projetos reais em Go.

O que é um map

Um map é uma coleção não ordenada de pares chave-valor, onde cada chave é única. Em Go, a sintaxe básica é:

var m map [string]int

Isso declara um map onde as chaves são strings e os valores são inteiros. Porém, antes de usar, você precisa inicializá-lo.

Criando e inicializando maps

Existem várias formas de criar maps em Go:

// Usando make
m1 := make(`**`map`**`[string]int) m1["nome"] = 25
// Com valores iniciais
m2 := map [string]int{     
    "idade": 30,     
    "anos":  5, 
}
// Map vazio
m3 := map [string]int{} 
// Map com tipos diferentes
m4 := map [string]string{     
    "nome":  "João",     
    "email": "joao@email.com", 
}

A função make é útil quando você vai adicionar elementos gradualmente. Já a sintaxe com valores iniciais é prática quando você já conhece os dados.

Adicionando e acessando elementos

Para adicionar ou modificar elementos, use a sintaxe de indexação:

m := make(map [string]int)// Adicionar
m["idade"] = 25 
m["anos"] = 10// Acessar
fmt.Println(m["idade"])// 25
m["idade"] = 26 // Modificar 
fmt.Println(m["idade"])// 26

Se você acessar uma chave que não existe, o map retorna o valor zero do tipo:

fmt.Println(m["inexistente"])// 0 (valor zero de int)

Verificando se uma chave existe

Uma particularidade importante dos maps em Go é que você pode verificar se uma chave existe usando um segundo valor de retorno:

m := map [string]int{
     "idade": 25, 
}  
valor, existe := m["idade"] fmt.Println(valor, existe)// 25 true 
valor, existe = m["nome"] fmt.Println(valor, existe)// 0 false

Isso é muito útil para evitar confusão entre um valor zero legítimo e uma chave inexistente.

Removendo elementos

Para remover uma chave do map, use a função delete:

m := map [string]int{     "idade": 25,     "anos":  10, }  
delete(m, "anos") 
fmt.Println(m)// map[25]
// Se a chave não existir, delete não faz nada
delete(m, "inexistente")

O delete não retorna nada e não causa erro se a chave não existir.

Iterando sobre maps

Para percorrer um map, use o for com range:

m := map [string]int{
     "idade": 25,     
     "anos":  10,     
     "pontos": 100, 
}

for chave, valor := range m {     
 fmt.Printf("%s: %d\n", chave, valor) 
}

Se você só precisa das chaves, pode ignorar o valor:

for chave := range m {     fmt.Println(chave) }

Importante: maps em Go não mantêm ordem. A ordem de iteração é aleatória e pode mudar entre execuções.

Maps como referências

Maps em Go são referências. Isso significa que quando você passa um map para uma função, está passando uma referência para o mesmo map:

func modifica(m map [string]int) {
     m["novo"] = 999 
}
func main() {     
     m := map [string]int{"idade": 25}     
     modifica(m)     
     fmt.Println(m["novo"]) // 999 
}

Isso é eficiente, mas exige cuidado para não causar efeitos colaterais inesperados.

Tipos de chaves e valores

Maps em Go são flexíveis quanto aos tipos:

// Chave string, valor int
m1 := map [string]int{} // Chave int, valor string
m2 := map [int]string{}// Chave string, valor slice
m3 := map [string][]int{} // Chave string, valor struct type Pessoa struct {   Nome  string     Idade int } 
m4 := map [string]Pessoa{}// Map de maps m5 := map [string]map [string]int{}

A única restrição é que as chaves devem ser tipos comparáveis. Tipos como slices, maps e functions não podem ser chaves porque não suportam comparação com ==.

Verificando se um map é nil

Um map não inicializado tem valor nil:

var m map [string]int fmt.Println(m == nil)// true
// Tentar usar um map nil causa panic
// m["chave"] = 1  // panic!
// Inicialize antes de usar m = make(map[string]int) m["chave"] = 1

Sempre inicialize um map antes de adicionar elementos.

Boas práticas

Algumas dicas para trabalhar bem com maps:

  • Sempre inicialize: use make ou sintaxe literal antes de adicionar elementos.
  • Verifique existência: use o segundo valor de retorno para checar se uma chave existe.
  • Cuidado com ordem: maps não mantêm ordem de inserção.
  • Evite chaves não comparáveis: slices, maps e functions não podem ser chaves.
  • Use tipos adequados: escolha tipos de chave e valor que façam sentido para seu caso.

Exemplo de verificação segura:

if valor, existe := m["chave"]; existe {     
 fmt.Println("Valor:", valor) 
} else {     
 fmt.Println("Chave não existe") 
}

Exemplo prático

Um caso comum de uso é contar ocorrências:

func contarPalavras(texto string) map[string]int {     
 palavras := strings.Fields(texto)     
 contagem := make(map [string]int)
 for _, palavra := range palavras {
   contagem[palavra]++     
 }
 return contagem 
}

func main() {     
 texto := "go é bom go é rápido"     
 resultado := contarPalavras(texto)
 
 for palavra, qtd := range resultado {         
   fmt.Printf("%s: %d\n", palavra, qtd)    
 } 
}

Conclusão

Maps são uma das estruturas mais úteis em Go. Eles oferecem acesso rápido a dados através de chaves, são flexíveis quanto aos tipos e fáceis de usar. Porém, exigem atenção em relação à inicialização, ordem não garantida e tipos de chaves comparáveis.

Dominar maps é essencial para escrever código Go eficiente e organizar dados de forma clara e performática.