Sobes.tech
Middle

Come funziona una mappa in Go?

sobes.tech AI

Risposta dell'AI

La mappa in Go è implementata come una tabella hash.

I componenti principali della struttura map:

  • Funzione hash: Mappa le chiavi ai valori hash (numeri interi).
  • Array di bucket: Un insieme di liste o array dove vengono memorizzate le coppie chiave-valore. L'indice del bucket è determinato dal valore hash della chiave.
  • Gestione delle collisioni: Quando diverse chiavi hanno lo stesso hash (collisione), gli elementi con queste chiavi vengono memorizzati nello stesso bucket, di solito sotto forma di lista collegata o in un bucket di overflow.
  • Fattore di carico: Rapporto tra il numero di elementi e il numero di bucket. Quando si supera una soglia, viene eseguito un rehashing: viene creato un nuovo array di bucket più grande e tutti gli elementi dei bucket vecchi vengono spostati in quelli nuovi.

La struttura map in Go è rappresentata dal tipo hmap:

 type hmap struct {
    count     int // Numero di elementi
    flags     uint8 // Flags di stato
    B         uint8 // log_2 del numero di bucket (numero di bucket è 2^B)
    noverflow uint16 // Numero di bucket con overflow (solo per statistiche)
    hash0     uint32 // Valore iniziale della funzione hash

    buckets    unsafe.Pointer // Puntatore all'array di bucket (principale e overflow)
    oldbuckets unsafe.Pointer // Puntatore all'array di bucket vecchio durante la migrazione
    nevacuate  uintptr // Indica fino a quale bucket vecchio è stata completata la migrazione

    extra *mapextra // Informazioni aggiuntive (opzionale)
}

 type mapextra struct {
    overflow    *[2]*[]*bmap // Puntatori ad array di bucket di overflow
    oldoverflow *[2]*[]*bmap // Puntatori ad array di bucket di overflow vecchi
    nextOverflow *bmap // Il prossimo bucket di overflow libero
}

 type bmap struct {
    tophash [8]uint8 // Top hash (bit superiori dell'hash) per accelerare la ricerca nel bucket
    // Segue chiavi, valori e puntatori al prossimo bmap (se il bucket è saturo)
    // Disporre tutti i dati per hmap.buckets in un singolo blocco malloc
    // vedi ../../runtime/map.go per i dettagli
}

Operazioni:

  • Inserimento/Aggiornamento: Si calcola l'hash della chiave, si determina il bucket. Se la chiave esiste già, il valore viene aggiornato. Altrimenti, la coppia chiave-valore viene aggiunta al bucket. In caso di overflow o superamento del Load Factor, può avvenire un rehashing.
  • Ricerca: Si calcola l'hash della chiave, si determina il bucket. Si percorrono gli elementi nel bucket per top-hash, poi si confrontano le chiavi complete. Viene restituito il valore e un flag di presenza.
  • Eliminazione: Si calcola l'hash della chiave, si determina il bucket. L'elemento viene contrassegnato come eliminato (ma non rimosso immediatamente dalla memoria). L'eliminazione avviene in operazioni successive o durante il rehashing.

La mappa in Go non è sincronizzata e non può essere usata in modo sicuro da più goroutine senza sincronizzazione esterna.