Ma

Maps in Go

2 esercizi

Informazioni su Maps

In Go, map è un tipo di dato integrato che rappresenta una tabella hash. In altri linguaggi di programmazione potresti conoscere la map come dict, come array associativo o come archivio chiave/valore. Se non hai familiarità con questo concetto, puoi pensare a map come a un dizionario, in cui ogni parola è la key e la definizione è l'element della map.

Prima di iniziare, ti segnalo la specifica di Go sulle map e il blog di Go sulle map per approfondire la map.

Dal punto di vista sintattico, una map si presenta così:

map[KeyType]ElementType

KeyType deve essere un qualsiasi tipo confrontabile, mentre ElementType può essere un qualsiasi tipo valido in Go: puoi memorizzare qualsiasi cosa, da una variabile primitiva a una slice.

È importante ricordare che map in Go è non ordinata: se provi a scorrerla con un ciclo e a stampare gli elementi, potresti sorprenderti vedendoli apparire in ordine casuale (provalo, se ti va).

È anche importante sapere che ogni chiave è unica: assegnare due volte la stessa chiave sovrascrive il valore della chiave corrispondente.

map è un tipo di riferimento, il che significa che se la passi in giro, Go non copia l'intera map. Go copia invece il puntatore della map: questo rende economico passare una map a una funzione o a una variabile. Il valore di una map non inizializzata è nil.

Puoi definire una map così (la chiamiamo anche nil map):

  var foo map[string]int

Per inizializzare una map, puoi fare così:

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

oppure

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

Una nil map è diversa da una map inizializzata: scrivere in una nil map causa un errore a runtime

panic: assignment to entry in nil map

Per questo è importante inizializzare una map prima di usarla

Ecco alcune operazioni che puoi fare con una 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 provi a recuperare il valore di una chiave che non esiste nella map, otterrai il valore zero del tipo del valore. Questo può confonderti, soprattutto se il valore predefinito del tuo ElementType (ad esempio 0 per un int) è un valore valido. Per verificare se una chiave esiste nella tua map, puoi usare

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

Come abbiamo visto prima, capire se una map è inizializzata o no è facile: basta confrontarla con nil. Ma che dire delle altre map? Dato che map non è confrontabile, non possiamo usare l'operatore ==, ma il pacchetto reflect ha qualcosa che ci viene in soccorso: si chiama DeepEqual, e possiamo usarlo così

import "reflect"

// ....

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

Ma aspetta, se map non è confrontabile, perché possiamo confrontarla con nil? La specifica ha fatto un'eccezione: vedi la specifica sui confronti

Un'ultima cosa: se provi a scrivere in una map da più goroutine, questo attiverà il rilevatore di race condition: vedi la documentazione di Go e il blog di Go. In alternativa, puoi usare sync.Map, atomic o mutex per aggirare questo problema.

Modifica tramite GitHub Il collegamento si apre in una nuova finestra o scheda

Impara Maps

La pratica è bloccata

Sblocca 3 altri esercizi per esercitarti su Maps