Ma

Mapas em Go

2 exercícios

Sobre Mapas

Em Go, map é um tipo de dado embutido que representa uma tabela hash. Em outras linguagens de programação, você pode conhecer o map como dict, array associativo ou um armazenamento de chave/valor. Se esse conceito não é familiar para você, pode pensar no map como um dicionário, em que cada palavra é a key e a definição é o element do map.

Antes de começarmos, quero te indicar a especificação do Go para map e o blog do Go sobre map para você se aprofundar mais no map.

Sintaticamente, o map é assim:

map[KeyType]ElementType

KeyType precisa ser qualquer tipo comparável, enquanto ElementType pode ser qualquer tipo válido em Go, o que significa que você pode armazenar qualquer coisa, de uma variável primitiva a um slice.

É importante lembrar que o map em Go não tem ordem definida: se você tentar iterar sobre um map e imprimir os elementos, pode se surpreender ao ver que eles aparecem em ordem aleatória (experimente, se quiser).

Também é importante saber que cada chave é única, ou seja, atribuir a mesma chave duas vezes sobrescreve o valor da chave correspondente.

O map é um tipo de referência, o que significa que, se você o passar adiante, o Go não copia o map inteiro. Em vez disso, o Go copia o ponteiro do map, o que torna barato passar um map para uma função ou variável. O valor de um map não inicializado é nil.

Você pode definir um map assim (também chamamos isso de map nil);

  var foo map[string]int

Para inicializar um map, você pode fazer:

  // With map literal
  foo := map[string]int{}

ou

  // or with make function
  foo := make(map[string]int)

Um map nil é diferente de um map inicializado: escrever em um map nil causa um erro em tempo de execução

panic: assignment to entry in nil map

Portanto, é importante inicializar um map antes de usá-lo

Aqui estão algumas operações que você pode fazer com um map

  // Add a value in a map with the `=` operator:
  foo["bar"] = 42
  // Here we update the element of `bar`
  foo["bar"] = 73
  // To retrieve a map value, you can use
  baz := foo["bar"]
  // To delete an item from a map, you can use
  delete(foo, "bar")

Se você tentar recuperar o valor de uma chave que não existe no map, ele retorna o valor zero do tipo do valor. Isso pode confundir você, especialmente se o valor padrão do seu ElementType (por exemplo, 0 para um int) for um valor válido. Para verificar se uma chave existe no seu map, você pode usar

  value, exists := foo["baz"]
  // If the key "baz" does not exist,
  // value: 0; exists: false

Como vimos antes, detectar se um map está inicializado ou não é fácil: basta compará-lo com nil. Mas e quanto a outros maps? Bem, como map não é comparável, não podemos usar o operador ==, mas o pacote reflect tem algo para nos salvar, chamado DeepEqual, que podemos usar assim

import "reflect"

// ....

equal := reflect.DeepEqual(map[string]int{}, map[string]int{})
fmt.Println(equal)
// Output: true

Mas espere: se map não é comparável, por que conseguimos compará-lo com nil? Bem, a especificação abriu uma exceção para isso, veja a especificação de comparáveis

Por último, se você tentar escrever em um map a partir de várias goroutines, isso vai disparar o detector de corrida; veja a documentação do Go e o The Go Blog. Como alternativa, você pode usar sync.Map, atomic ou mutex para contornar esse problema.

Editar via GitHub O link abre em uma nova janela ou aba

Aprenda Mapas

A prática está bloqueada

Desbloqueie mais 3 exercícios para praticar Mapas