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")
}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow