Middle
Cum funcționează un Map în Go?
sobes.tech AI
Răspuns de la AI
Map în Go este implementată ca o tabelă hash.
Componentele principale ale structurii map:
- Funcție hash: Mapază cheile la valori hash (numere întregi).
- Array de bucket-uri: Un set de liste sau array-uri unde sunt stocate perechile cheie-valoare. Indicele bucket-ului este determinat de valoarea hash a cheii.
- Gestionarea coliziunilor: Când diferite chei au același hash (coliziune), elementele cu aceste chei sunt stocate în același bucket, de obicei sub formă de listă legată sau bucket de overflow.
- Factor de încărcare: Raportul dintre numărul de elemente și numărul de bucket-uri. Când se depășește un prag, se face un rehashing: se creează un nou array de bucket-uri mai mare și toate elementele din bucket-urile vechi sunt mutate în cele noi.
Structura map în Go este reprezentată de tipul hmap:
type hmap struct {
count int // Numărul de elemente
flags uint8 // Flag-uri de stare
B uint8 // log_2 al numărului de bucket-uri (numărul de bucket-uri este 2^B)
noverflow uint16 // Numărul de bucket-uri cu overflow (doar pentru statistici)
hash0 uint32 // Valoarea inițială a funcției hash
buckets unsafe.Pointer // Punter către array-ul de bucket-uri (principal și overflow)
oldbuckets unsafe.Pointer // Punter către array-ul vechi de bucket-uri în timpul migrației
nevacuate uintptr // Indică până la care bucket vechi s-a finalizat migrația
extra *mapextra // Informații suplimentare (opțional)
}
type mapextra struct {
overflow *[2]*[]*bmap // Pointers către array-uri de bucket-uri de overflow
oldoverflow *[2]*[]*bmap // Pointers către array-uri vechi de bucket-uri de overflow
nextOverflow *bmap // Următorul bucket de overflow liber
}
type bmap struct {
tophash [8]uint8 // Top hash (bitii superiori ai hash-ului) pentru accelerarea căutării în bucket
// Urmează cheile, valorile și pointerii către următorul bmap (dacă bucket-ul este plin)
// Distribuie toate datele pentru hmap.buckets într-un singur bloc malloc
// vezi ../../runtime/map.go pentru detalii
}
Operații:
- Inserare/Actualizare: Se calculează hash-ul cheii, se determină bucket-ul. Dacă cheia există deja, valoarea se actualizează. Altfel, perechea cheie-valoare se adaugă în bucket. La overflow sau depășirea Load Factor, poate avea loc o rehashare.
- Căutare: Se calculează hash-ul cheii, se determină bucket-ul. Se parcurg elementele din bucket după top-hash, apoi se compară cheile complete. Se returnează valoarea și un flag de existență.
- Ștergere: Se calculează hash-ul cheii, se determină bucket-ul. Elementul este marcat ca șters (dar nu este șters imediat din memorie). Ștergerea are loc în operațiile ulterioare sau în timpul rehash-ului.
Map-ul în Go nu este sincronizat și nu poate fi utilizat în siguranță de mai multe goroutine fără sincronizare externă.