ProgrammazioneSviluppatore Go

Как работает map[string]struct{} как set в Go и каковы особенности такого применения?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della domanda:

Go di default non ha una struttura Set, ma spesso si presenta la necessità di lavorare con elementi unici. La struttura ottimale è il map[string]struct{}, dove la chiave è l'elemento e la struttura vuota funge da "etichetta di presenza". Questo è un pattern comune per test di appartenenza rapidi.

Problema:

La mancanza di un Set incorporato porta i neofiti a trovare difficile implementare correttamente collezioni uniche. È inoltre necessario capire perché struct{} sia più efficiente di bool o int come valore.

Soluzione:

Per implementare un Set in Go si utilizza map[string]struct{}. La struttura vuota struct{} non richiede memoria (zero-sized), mentre la map fornisce un accesso veloce. Esempio:

set := make(map[string]struct{}) set["foo"] = struct{}{} if _, ok := set["foo"]; ok { fmt.Println("Presente") } delete(set, "foo")

Caratteristiche principali:

  • struct{} occupa 0 byte — implementazione economica
  • map offre accesso O(1) per chiave
  • Nessuna duplicazione di elementi, la semantica Set è facilmente implementabile

Domande ingannevoli.

Perché non si può usare slice/array come valore?

slice/array per set non forniscono tempo di ricerca costante — bisognerebbe scorrere tutti i valori, il che è lento.

Qual è la differenza tra map[string]struct{} e map[string]bool?

map[string]bool occupa più memoria: per ogni chiave memorizza un bool, mentre struct{} è un tipo vuoto che non alloca nulla.

set := map[string]bool{"foo": true}

Si può usare int invece di struct{}?

Si può, ma int occupa sempre memoria. struct{} è universale: se è necessaria solo la funzione di "etichetta" (presenza), è migliore.

set := map[string]int{"foo": 1} // ma memorizza (chiave -> numero)

Errori comuni e anti-pattern

  • Usare bool o int per valori senza necessità
  • Usare slice per cercare la presenza di un elemento (rallenta i controlli)
  • Dimenticarsi di rimuovere elementi tramite delete

Esempio dalla vita reale

Caso negativo

A causa dell'ignoranza è stato assegnato map[string]bool per un insieme di indirizzi IP unici. Di conseguenza, con milioni di indirizzi, l'uso di memoria è raddoppiato rispetto a struct{}.

Pro:

  • Semanticamente chiaro (true == c'è)

Contro:

  • Prestazioni inferiori
  • Maggiore consumo di memoria

Caso positivo

Nel progetto per memorizzare email uniche è stato usato map[string]struct{}. Il carico è diminuito, ha lavorato più velocemente, la memoria quasi non è stata spesa per i valori.

Pro:

  • Overhead minimo
  • Prestazioni su un numero elevato di elementi

Contro:

  • Meno ovvio per i neofiti, richiede commento nel codice