Ricerca…
introduzione
Le mappe sono tipi di dati utilizzati per l'archiviazione di coppie chiave-valore non ordinate, in modo che la ricerca del valore associato a una determinata chiave sia molto efficiente. Le chiavi sono uniche. La struttura dei dati sottostanti cresce come necessario per accogliere nuovi elementi, quindi il programmatore non deve preoccuparsi della gestione della memoria. Sono simili a quelli che altri linguaggi chiamano tabelle hash, dizionari o array associativi.
Sintassi
- var mapName map [KeyType] ValueType // dichiara una mappa
- var mapName = map [KeyType] ValueType {} // dichiara e assegna una mappa vuota
- var mapName = map [KeyType] ValueType {key1: val1, key2: val2} // dichiara e assegna una mappa
- mapName: = make (map [KeyType] ValueType) // dichiara e inizializza la mappa delle dimensioni di default
- mapName: = make (map [KeyType] ValueType, length) // dichiara e inizializza la mappa delle dimensioni della lunghezza
- mapName: = map [KeyType] ValueType {} // auto-dichiara e assegna una mappa vuota con: =
- mapName: = map [KeyType] ValueType {key1: value1, key2: value2} // auto-dichiara e assegna una mappa con: =
- valore: = mapName [chiave] // Ottieni valore per chiave
- value, hasKey: = mapName [chiave] // Ottieni valore per chiave, 'hasKey' è 'true' se la chiave esiste nella mappa
- mapName [chiave] = valore // Imposta valore per chiave
Osservazioni
Go fornisce un tipo di map
integrato che implementa una tabella hash . Le mappe sono tipi di dati associativi integrati di Go (chiamati anche hash o dizionari in altre lingue).
Dichiarazione e inizializzazione di una mappa
Definisci una mappa usando la map
parole chiave, seguita dai tipi delle sue chiavi e dai suoi valori:
// Keys are ints, values are ints.
var m1 map[int]int // initialized to nil
// Keys are strings, values are ints.
var m2 map[string]int // initialized to nil
Le mappe sono tipi di riferimento e, una volta definiti, hanno un valore zero pari a nil
. Scrive su zero le mappe andranno nel panico e le letture restituiranno sempre il valore zero.
Per inizializzare una mappa, usa la funzione make
:
m := make(map[string]int)
Con la forma a due parametri di make
, è possibile specificare una capacità di immissione iniziale per la mappa, ignorando la capacità predefinita:
m := make(map[string]int, 30)
In alternativa, è possibile dichiarare una mappa, inizializzarla sul suo valore zero e quindi assegnarvi un valore letterale in seguito, il che aiuta se si effettua il marshalling della struct in json producendo quindi una mappa vuota al momento del ritorno.
m := make(map[string]int, 0)
Puoi anche creare una mappa e impostare il suo valore iniziale con parentesi graffe ( {}
).
var m map[string]int = map[string]int{"Foo": 20, "Bar": 30}
fmt.Println(m["Foo"]) // outputs 20
Tutte le seguenti istruzioni fanno sì che la variabile sia associata allo stesso valore.
// Declare, initializing to zero value, then assign a literal value.
var m map[string]int
m = map[string]int{}
// Declare and initialize via literal value.
var m = map[string]int{}
// Declare via short variable declaration and initialize with a literal value.
m := map[string]int{}
Possiamo anche usare una mappa letterale per creare una nuova mappa con alcune coppie chiave / valore iniziali .
Il tipo di chiave può essere di qualsiasi tipo comparabile ; in particolare, questo esclude funzioni, mappe e sezioni . Il tipo di valore può essere di qualsiasi tipo, inclusi i tipi personalizzati o l' interface{}
.
type Person struct {
FirstName string
LastName string
}
// Declare via short variable declaration and initialize with make.
m := make(map[string]Person)
// Declare, initializing to zero value, then assign a literal value.
var m map[string]Person
m = map[string]Person{}
// Declare and initialize via literal value.
var m = map[string]Person{}
// Declare via short variable declaration and initialize with a literal value.
m := map[string]Person{}
Creare una mappa
Si può dichiarare e inizializzare una mappa in una singola istruzione usando un letterale composito .
Utilizzo del tipo automatico Breve dichiarazione variabile:
mapIntInt := map[int]int{10: 100, 20: 100, 30: 1000}
mapIntString := map[int]string{10: "foo", 20: "bar", 30: "baz"}
mapStringInt := map[string]int{"foo": 10, "bar": 20, "baz": 30}
mapStringString := map[string]string{"foo": "one", "bar": "two", "baz": "three"}
Lo stesso codice, ma con tipi Variabili:
var mapIntInt = map[int]int{10: 100, 20: 100, 30: 1000}
var mapIntString = map[int]string{10: "foo", 20: "bar", 30: "baz"}
var mapStringInt = map[string]int{"foo": 10, "bar": 20, "baz": 30}
var mapStringString = map[string]string{"foo": "one", "bar": "two", "baz": "three"}
Puoi anche includere le tue strutture in una mappa:
Puoi usare i tipi personalizzati come valore:
// Custom struct types
type Person struct {
FirstName, LastName string
}
var mapStringPerson = map[string]Person{
"john": Person{"John", "Doe"},
"jane": Person{"Jane", "Doe"}}
mapStringPerson := map[string]Person{
"john": Person{"John", "Doe"},
"jane": Person{"Jane", "Doe"}}
La tua struttura può anche essere la chiave per la mappa:
type RouteHit struct {
Domain string
Route string
}
var hitMap = map[RouteHit]int{
RouteHit{"example.com","/home"}: 1,
RouteHit{"example.com","/help"}: 2}
hitMap := map[RouteHit]int{
RouteHit{"example.com","/home"}: 1,
RouteHit{"example.com","/help"}: 2}
Puoi creare una mappa vuota semplicemente non inserendo alcun valore tra parentesi {}
.
mapIntInt := map[int]int{}
mapIntString := map[int]string{}
mapStringInt := map[string]int{}
mapStringString := map[string]string{}
mapStringPerson := map[string]Person{}
È possibile creare e utilizzare direttamente una mappa, senza la necessità di assegnarla a una variabile. Tuttavia, dovrai specificare sia la dichiarazione che il contenuto.
// using a map as argument for fmt.Println()
fmt.Println(map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Age": "30"})
// equivalent to
data := map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Age": "30"}
fmt.Println(data)
Valore zero di una mappa
Il valore zero di una map
è nil
e ha una lunghezza pari a 0
.
var m map[string]string
fmt.Println(m == nil) // true
fmt.Println(len(m) ==0) // true
Una mappa nil
non ha chiavi e non è possibile aggiungere le chiavi. Una mappa nil
si comporta come una mappa vuota se letta da ma provoca un panico di runtime se viene scritta.
var m map[string]string
// reading
m["foo"] == "" // true. Remember "" is the zero value for a string
_, ok = m["foo"] // ok == false
// writing
m["foo"] = "bar" // panic: assignment to entry in nil map
Non dovresti provare a leggere o scrivere su una mappa a valore zero. Invece, inizializza la mappa (con make
o assignment) prima di usarla.
var m map[string]string
m = make(map[string]string) // OR m = map[string]string{}
m["foo"] = "bar"
Iterazione degli elementi di una mappa
import fmt
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, value := range people {
fmt.Println("Name:", key, "Age:", value)
}
Nota che durante l'iterazione su una mappa con un loop di intervallo, l'ordine di iterazione non è specificato e non è garantito che sia lo stesso da una iterazione alla successiva.
Puoi anche scartare le chiavi o i valori della mappa, se stai cercando di afferrare le chiavi o semplicemente di prendere i valori.
Iterazione delle chiavi di una mappa
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, _ := range people {
fmt.Println("Name:", key)
}
Se stai solo cercando le chiavi, dato che sono il primo valore, puoi semplicemente eliminare il carattere di sottolineatura:
for key := range people {
fmt.Println("Name:", key)
}
Nota che durante l'iterazione su una mappa con un loop di intervallo, l'ordine di iterazione non è specificato e non è garantito che sia lo stesso da una iterazione alla successiva.
Eliminazione di un elemento della mappa
La funzione integrata di delete
rimuove l'elemento con la chiave specificata da una mappa.
people := map[string]int{"john": 30, "jane": 29}
fmt.Println(people) // map[john:30 jane:29]
delete(people, "john")
fmt.Println(people) // map[jane:29]
Se la map
è nil
o non esiste alcun elemento, l' delete
non ha alcun effetto.
people := map[string]int{"john": 30, "jane": 29}
fmt.Println(people) // map[john:30 jane:29]
delete(people, "notfound")
fmt.Println(people) // map[john:30 jane:29]
var something map[string]int
delete(something, "notfound") // no-op
Conteggio degli elementi della mappa
La funzione built-in len
restituisce il numero di elementi in una map
m := map[string]int{}
len(m) // 0
m["foo"] = 1
len(m) // 1
Se una variabile punta a una mappa nil
, allora len
restituisce 0.
var m map[string]int
len(m) // 0
Accesso simultaneo di mappe
Le mappe in go non sono sicure per la concorrenza. È necessario prendere un lucchetto per leggere e scrivere su di essi se si accederà a loro in contemporanea. In genere, l'opzione migliore è utilizzare sync.RWMutex
perché è possibile avere blocchi di lettura e scrittura. Tuttavia, è anche possibile utilizzare un sync.Mutex
.
type RWMap struct {
sync.RWMutex
m map[string]int
}
// Get is a wrapper for getting the value from the underlying map
func (r RWMap) Get(key string) int {
r.RLock()
defer r.RUnlock()
return r.m[key]
}
// Set is a wrapper for setting the value of a key in the underlying map
func (r RWMap) Set(key string, val int) {
r.Lock()
defer r.Unlock()
r.m[key] = val
}
// Inc increases the value in the RWMap for a key.
// This is more pleasant than r.Set(key, r.Get(key)++)
func (r RWMap) Inc(key string) {
r.Lock()
defer r.Unlock()
r.m[key]++
}
func main() {
// Init
counter := RWMap{m: make(map[string]int)}
// Get a Read Lock
counter.RLock()
_ = counter.["Key"]
counter.RUnlock()
// the above could be replaced with
_ = counter.Get("Key")
// Get a write Lock
counter.Lock()
counter.m["some_key"]++
counter.Unlock()
// above would need to be written as
counter.Inc("some_key")
}
Il compromesso tra le funzioni del wrapper è tra l'accesso pubblico della mappa sottostante e l'uso corretto dei blocchi appropriati.
Creazione di mappe con sezioni come valori
m := make(map[string][]int)
L'accesso a una chiave inesistente restituirà una fetta nil come valore. Poiché le porzioni nil si comportano come sezioni a lunghezza zero quando vengono utilizzate con append
o altre funzioni integrate di solito non è necessario verificare se esiste una chiave:
// m["key1"] == nil && len(m["key1"]) == 0
m["key1"] = append(m["key1"], 1)
// len(m["key1"]) == 1
L'eliminazione di una chiave dalla mappa riporta la chiave su una fetta nullo:
delete(m, "key1")
// m["key1"] == nil
Controlla l'elemento in una mappa
Per ottenere un valore dalla mappa, devi solo fare qualcosa del tipo: 00
value := mapName[ key ]
Se la mappa contiene la chiave, restituisce il valore corrispondente.
In caso contrario, restituisce valore zero del tipo di valore della mappa ( 0
se mappa di valori int
, ""
se mappa di valori string
...)
m := map[string]string{"foo": "foo_value", "bar": ""}
k := m["foo"] // returns "foo_value" since that is the value stored in the map
k2 := m["bar"] // returns "" since that is the value stored in the map
k3 := m["nop"] // returns "" since the key does not exist, and "" is the string type's zero value
Per distinguere tra valori vuoti e chiavi inesistenti, è possibile utilizzare il secondo valore restituito dell'accesso alla mappa (utilizzando il value, hasKey := map["key"]
simile value, hasKey := map["key"]
).
Questo secondo valore è boolean
digitato e sarà:
-
true
quando il valore è nella mappa, -
false
quando la mappa non contiene la chiave indicata.
Guarda il seguente esempio:
value, hasKey = m[ key ]
if hasKey {
// the map contains the given key, so we can safely use the value
// If value is zero-value, it's because the zero-value was pushed to the map
} else {
// The map does not have the given key
// the value will be the zero-value of the map's type
}
Iterazione dei valori di una mappa
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for _, value := range people {
fmt.Println("Age:", value)
}
Nota che durante l'iterazione su una mappa con un loop di intervallo, l'ordine di iterazione non è specificato e non è garantito che sia lo stesso da una iterazione alla successiva.
Copia una mappa
Come le sezioni, le mappe contengono riferimenti a una struttura dati sottostante. Quindi assegnando il suo valore a un'altra variabile, verrà passato solo il riferimento. Per copiare la mappa, è necessario creare un'altra mappa e copiare ogni valore:
// Create the original map
originalMap := make(map[string]int)
originalMap["one"] = 1
originalMap["two"] = 2
// Create the target map
targetMap := make(map[string]int)
// Copy from the original map to the target map
for key, value := range originalMap {
targetMap[key] = value
}
Usare una mappa come set
Alcune lingue hanno una struttura nativa per insiemi. Per creare un set in Go, è consigliabile utilizzare una mappa dal tipo di valore del set su una struttura vuota ( map[Type]struct{}
).
Ad esempio, con le stringhe:
// To initialize a set of strings:
greetings := map[string]struct{}{
"hi": {},
"hello": {},
}
// To delete a value:
delete(greetings, "hi")
// To add a value:
greetings["hey"] = struct{}{}
// To check if a value is in the set:
if _, ok := greetings["hey"]; ok {
fmt.Println("hey is in greetings")
}