Come verificare se una mappa contiene una chiave in uscita?

So che posso scorrere su una mappa m by,

for k, v := range m { ... } 

e cercare una chiave ma c’è un modo più efficiente di testare l’esistenza di una chiave in una mappa? Grazie. Non sono riuscito a trovare una risposta nelle specifiche del linguaggio .

Una risposta in linea:

 if val, ok := dict["foo"]; ok { //do something here } 

Spiegazione:

if istruzioni in Go possono includere sia una condizione che un’istruzione di inizializzazione. L’esempio sopra utilizza entrambi:

  • inizializza due variabili – val riceverà il valore di “foo” dalla mappa o un “valore zero” (in questo caso la stringa vuota) e ok riceverà un bool che verrà impostato su true se “foo” fosse effettivamente presente nella mappa

  • valuta ok , che sarà true se “pippo” era nella mappa

Se “foo” è effettivamente presente nella mappa, il corpo dell’istruzione if verrà eseguito e val sarà locale a tale scope.

Modifica: la risposta che segue è precedente a Vai 1. A partire da Vai 1, non è più preciso / valido.


Oltre alla specifica del linguaggio di programmazione Go , è necessario leggere Effective Go . Nella sezione sulle mappe , dicono, tra le altre cose:

“Un tentativo di recuperare un valore di una mappa con una chiave che non è presente nella mappa causerà il crash del programma, ma c’è un modo per farlo in sicurezza usando un incarico multiplo.”

 var seconds int var ok bool seconds, ok = timeZone[tz] 

“Per verificare la presenza sulla mappa senza preoccuparsi del valore effettivo, è ansible utilizzare l’identificativo vuoto, un semplice trattino di sottolineatura (_). L’identificatore vuoto può essere assegnato o dichiarato con qualsiasi valore di qualsiasi tipo, con il valore scartato senza problemi. Per verificare la presenza in una mappa, utilizzare l’identificatore vuoto al posto della variabile normale per il valore. ”

 _, present := timeZone[tz] 

Ho cercato nella mailing list dei go-nuts e trovato una soluzione pubblicata da Peter Froehlich il 15/11/2009.

 package main import "fmt" func main() { dict := map[string]int {"foo" : 1, "bar" : 2} value, ok := dict["baz"] if ok { fmt.Println("value: ", value) } else { fmt.Println("key not found") } } 

O, in modo più compatto,

 if value, ok := dict["baz"]; ok { fmt.Println("value: ", value) } else { fmt.Println("key not found") } 

Nota, usando questo modulo dell’istruzione if , il value e le variabili ok sono visibili solo all’interno delle condizioni if .

Risposta breve

 _, exists := timeZone[tz] // Just checks for key existence val, exists := timeZone[tz] // Checks for key existence and retrieves the value 

Esempio

Ecco un esempio al Go Playground .

Risposta più lunga

Per la sezione Maps di Go efficace :

Un tentativo di recuperare un valore di una mappa con una chiave che non è presente nella mappa restituirà il valore zero per il tipo di voci nella mappa. Ad esempio, se la mappa contiene numeri interi, la ricerca di una chiave inesistente restituirà 0.

A volte è necessario distinguere una voce mancante da un valore zero. C’è una voce per “UTC” o è la stringa vuota perché non è nella mappa? Puoi discriminare con una forma di assegnazione multipla.

 var seconds int var ok bool seconds, ok = timeZone[tz] 

Per ovvi motivi questo è chiamato l’idioma “virgola ok”. In questo esempio, se tz è presente, i secondi saranno impostati in modo appropriato e ok sarà vero; in caso contrario, i secondi saranno impostati su zero e ok sarà falso. Ecco una funzione che la mette insieme a un bel report di errore:

 func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 } 

Per verificare la presenza sulla mappa senza preoccuparsi del valore effettivo, è ansible utilizzare l’identificativo vuoto (_) al posto della variabile normale per il valore.

 _, present := timeZone[tz] 

Come notato da altre risposte, la soluzione generale è usare un’espressione di indice in un incarico della forma speciale:

 v, ok = a[x] v, ok := a[x] var v, ok = a[x] var v, ok T = a[x] 

Questo è carino e pulito. Ha alcune restrizioni però: deve essere un incarico di forma speciale. L’espressione lato destro deve essere solo l’espressione dell’indice della mappa e l’elenco di espressioni di sinistra deve contenere esattamente 2 operandi, il primo al quale il tipo di valore è assegnabile e un secondo al quale è ansible assegnare un valore bool . Il primo valore del risultato di questa espressione di indice di forma speciale sarà il valore associato alla chiave e il secondo valore indicherà se c’è effettivamente una voce nella mappa con la chiave specificata (se la chiave esiste nella mappa). L’elenco di espressioni sul lato sinistro può contenere anche l’ identificatore vuoto se uno dei risultati non è necessario.

È importante sapere che se il valore della mappa indicizzata è nil o non contiene la chiave, l’espressione di indice restituisce il valore zero del tipo di valore della mappa. Quindi per esempio:

 m := map[int]string{} s := m[1] // s will be the empty string "" var m2 map[int]float64 // m2 is nil! f := m2[2] // f will be 0.0 fmt.Printf("%q %f", s, f) // Prints: "" 0.000000 

Provalo su Go Playground .

Quindi, se sappiamo che non usiamo il valore zero nella nostra mappa, possiamo trarne vantaggio.

Ad esempio se il tipo di valore è string , e sappiamo che non memorizziamo mai voci nella mappa in cui il valore è la stringa vuota (valore zero per il tipo di string ), possiamo anche verificare se la chiave è nella mappa confrontando il non -forma speciale dell’espressione di indice (risultato di) al valore zero:

 m := map[int]string{ 0: "zero", 1: "one", } fmt.Printf("Key 0 exists: %t\nKey 1 exists: %t\nKey 2 exists: %t", m[0] != "", m[1] != "", m[2] != "") 

Output (provalo su Go Playground ):

 Key 0 exists: true Key 1 exists: true Key 2 exists: false 

In pratica ci sono molti casi in cui non memorizziamo il valore del valore zero nella mappa, quindi questo può essere usato abbastanza spesso. Ad esempio, le interfacce e i tipi di funzione hanno un valore nil , che spesso non memorizziamo nelle mappe. Quindi, testare se una chiave è presente nella mappa può essere ottenuta confrontandola con nil .

L’utilizzo di questa “tecnica” ha anche un altro vantaggio: è ansible verificare l’esistenza di più chiavi in ​​modo compatto (non è ansible farlo con il modulo speciale “virgola ok”). Ulteriori informazioni su questo: verificare se la chiave esiste in più mappe in una condizione

modo migliore qui

 if _, ok := dict["foo"]; ok { //do something here } 
  var empty struct{} var ok bool var m map[string]struct{} m = make(map[string]struct{}) m["somestring"] = empty _, ok = m["somestring"] fmt.Println("somestring exists?", ok) _, ok = m["not"] fmt.Println("not exists?", ok) 

Quindi, vai a correre maps.go somestring esiste? vero non esiste? falso

È menzionato sotto “Espressioni dell’indice” .

Un’espressione di indice su una mappa a di tipo map [K] V utilizzata in un’assegnazione o inizializzazione della forma speciale

 v, ok = a[x] v, ok := a[x] var v, ok = a[x] 

produce un valore booleano aggiuntivo non tipizzato. Il valore di ok è vero se la chiave x è presente nella mappa e false altrimenti.

Basta usare

 if len(m) == 0 { ... }