Sobes.tech
Middle

Como funciona o Map em Go?

sobes.tech IA

Resposta da IA

Map em Go é implementada como uma tabela de dispersão.

Os componentes principais da estrutura map:

  • Função de hash: Mapeia as chaves para valores de hash (números inteiros).
  • Array de buckets: Conjunto de listas ou arrays onde são armazenados pares chave-valor. O índice do bucket é determinado pelo valor de hash da chave.
  • Gestão de colisões: Quando diferentes chaves têm o mesmo hash (colisão), os elementos com essas chaves são armazenados no mesmo bucket, geralmente em forma de lista ligada ou em um bucket de overflow.
  • Fator de carga: Relação entre o número de elementos e o número de buckets. Quando um limiar é ultrapassado, é realizado um rehashing: cria-se um novo array de buckets maior e move-se todos os elementos dos buckets antigos para os novos.

A estrutura map em Go é representada pelo tipo hmap:

 type hmap struct {
    count     int // Número de elementos
    flags     uint8 // Flags de estado
    B         uint8 // log_2 do número de buckets (número de buckets é 2^B)
    noverflow uint16 // Número de buckets com overflow (apenas para estatísticas)
    hash0     uint32 // Valor inicial da função de hash

    buckets    unsafe.Pointer // Ponteriro para o array de buckets (principal e overflow)
    oldbuckets unsafe.Pointer // Ponteriro para o array antigo de buckets durante a migração
    nevacuate  uintptr // Indica até que bucket antigo a migração foi concluída

    extra *mapextra // Informação adicional (opcional)
}

 type mapextra struct {
    overflow    *[2]*[]*bmap // Ponteriros para arrays de buckets de overflow
    oldoverflow *[2]*[]*bmap // Ponteriros para antigos arrays de buckets de overflow
    nextOverflow *bmap // Próximo bucket de overflow livre
}

 type bmap struct {
    tophash [8]uint8 // Top hash (bits superiores do hash) para acelerar a busca no bucket
    // Seguem-se as chaves, valores e ponteiros para o próximo bmap (se o bucket estiver cheio)
    // distribuir todos os dados para hmap.buckets num único bloco malloc
    // ver ../../runtime/map.go para detalhes
}

Operações:

  • Inserção/Atualização: Calcula-se o hash da chave, determina-se o bucket. Se a chave já existir, o valor é atualizado. Caso contrário, o par chave-valor é adicionado ao bucket. Em caso de overflow ou superação do Load Factor, pode ocorrer um rehashing.
  • Busca: Calcula-se o hash da chave, determina-se o bucket. Percorrem-se os elementos no bucket pelo top-hash, depois compara-se as chaves completas. Retorna-se o valor e um indicador de existência.
  • Remoção: Calcula-se o hash da chave, determina-se o bucket. O elemento é marcado como removido (mas não é removido imediatamente da memória). A remoção ocorre em operações posteriores ou durante o rehashing.

O mapa em Go não é sincronizado e não pode ser usado com segurança por múltiplas goroutines sem sincronização externa.