Je sais que je peux parcourir une carte m
by,
for k, v := range m { ... }
et cherchez une clé, mais existe-t-il un moyen plus efficace de tester l'existence d'une clé dans une carte?
Je n'ai pas trouvé de réponse dans le language spec .
Réponse en ligne:
if val, ok := dict["foo"]; ok {
//do something here
}
Les instructions if
dans Go peuvent inclure une condition et une instruction d'initialisation. L'exemple ci-dessus utilise à la fois:
initialise deux variables - val
recevra soit la valeur "foo" de la carte, soit une "valeur zéro" (dans ce cas, la chaîne vide) et ok
recevra un bool qui sera défini sur true
si "foo" était réellement présent dans la carte
évalue ok
, qui sera true
si "foo" était dans la carte
Si "foo" est effectivement présent dans la carte, le corps de l'instruction if
sera exécuté et val
sera local à cette étendue.
Edit: La réponse suivante est antérieure à Go 1. À partir de Go 1, elle n’est plus exacte/valide.
En plus de Spécification du langage de programmation Go , vous devez lire Effective Go . Dans la section sur cartes , ils disent entre autres:
"Une tentative d'extraction d'une valeur de la carte avec une clé qui n'est pas présente dans la carte provoquera le blocage du programme, mais il existe un moyen de le faire en toute sécurité en utilisant une affectation multiple."
var seconds int
var ok bool
seconds, ok = timeZone[tz]
"Pour tester la présence sur la carte sans se soucier de la valeur réelle, vous pouvez utiliser l'identifiant vide, un simple trait de soulignement (_). L'identifiant vide peut être attribué ou déclaré avec n'importe quelle valeur, de n'importe quel type, la valeur étant supprimée de manière inoffensive. Pour tester la présence dans une carte, utilisez l'identificateur vide à la place de la variable habituelle pour la valeur. "
_, present := timeZone[tz]
Vous avez cherché sur = liste de courrier électronique go-nut et trouvé une solution publiée par Peter Froehlich le 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")
}
}
Ou, plus compactement,
if value, ok := dict["baz"]; ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
Notez que, sous cette forme de l'instruction if
, les variables value
et ok
sont uniquement visibles dans les conditions if
.
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
Voici un exemple sur le terrain de je .
Selon la section Maps de Effective Go :
Une tentative d'extraction d'une valeur de carte avec une clé qui n'est pas présente dans la carte renverra la valeur zéro pour le type des entrées dans la carte. Par exemple, si la carte contient des entiers, la recherche d'une clé inexistante renverra 0.
Parfois, vous devez distinguer une entrée manquante d'une valeur nulle. Existe-t-il une entrée pour "UTC" ou s'agit-il d'une chaîne vide car elle ne figure pas du tout dans la carte? Vous pouvez discriminer avec une forme d'affectation multiple.
var seconds int var ok bool seconds, ok = timeZone[tz]
Pour des raisons évidentes, on appelle cela l'idiome "virgule ok". Dans cet exemple, si tz est présent, les secondes seront définies correctement et ok sera vrai; sinon, les secondes seront mises à zéro et ok sera faux. Voici une fonction qui associe un rapport d'erreur de Nice:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
Pour tester la présence dans la carte sans vous soucier de la valeur réelle, vous pouvez utiliser l'identificateur vide (_) à la place de la variable habituelle pour la valeur.
_, present := timeZone[tz]
Comme indiqué par d'autres réponses, la solution générale consiste à utiliser un expression d'index dans un affectation de la forme spéciale:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
C'est gentil et propre. Il y a cependant quelques restrictions: il doit s'agir d'une cession de forme spéciale. L'expression de droite doit être uniquement l'expression d'index-mappe et la liste des expressions de gauche doit contenir exactement 2 opérandes, le premier auquel le type de valeur est assignable et le second auquel une valeur bool
est assignable. La première valeur du résultat de cette expression d'index de formulaire spécial sera la valeur associée à la clé, et la deuxième valeur indiquera s'il existe réellement une entrée dans la carte avec la clé donnée (si la clé existe dans la carte). La liste des expressions de gauche peut également contenir le signe identificateur vide si l'un des résultats n'est pas nécessaire.
Il est important de savoir que si la valeur de la carte indexée est nil
ou ne contient pas la clé, l'expression d'index est évaluée à valeur zéro du type de valeur de la carte. Donc par exemple:
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
Essayez-le sur le Go Playground .
Donc, si nous savons que nous n'utilisons pas la valeur zéro dans notre carte, nous pouvons en tirer parti.
Par exemple, si le type de valeur est string
et que nous savons que nous ne stockons jamais d'entrées dans la mappe où la valeur est la chaîne vide (valeur zéro pour le type string
name__), nous pouvons également vérifier si la clé est dans la m - forme spéciale de l'expression d'index (résultat de) à la valeur zéro:
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] != "")
Sortie (essayez-le sur le Go Playground ):
Key 0 exists: true
Key 1 exists: true
Key 2 exists: false
En pratique, il existe de nombreux cas où nous ne stockons pas la valeur zéro dans la carte, ce qui peut être utilisé assez souvent. Par exemple, les interfaces et les types de fonction ont une valeur nulle nil
name__, que nous ne stockons souvent pas dans les cartes. Il est donc possible de vérifier si une clé figure sur la carte en la comparant à nil
name__.
L'utilisation de cette "technique" présente également un autre avantage: vous pouvez vérifier l'existence de plusieurs clés de manière compacte (vous ne pouvez pas le faire avec le formulaire spécial "comma ok"). Plus à ce sujet: Vérifiez si la clé existe dans plusieurs cartes dans une condition
meilleur moyen ici
if _, ok := dict["foo"]; ok {
//do something here
}
Il est mentionné sous "Index index" .
Une expression d'index sur une carte a de type map [K] V utilisée dans une assignation ou une initialisation de la forme spéciale
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
donne une valeur booléenne supplémentaire non typée. La valeur de ok est true si la clé x est présente dans la carte et false sinon.
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)
Ensuite, allez exécuter maps.go somestring existe? vrai n'existe pas? faux
Une affectation de deux valeurs peut être utilisée à cette fin. S'il vous plaît vérifier mon exemple de programme ci-dessous
package main
import (
"fmt"
)
func main() {
//creating a map with 3 key-value pairs
sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
//A two value assignment can be used to check existence of a key.
value, isKeyPresent := sampleMap["key2"]
//isKeyPresent will be true if key present in sampleMap
if isKeyPresent {
//key exist
fmt.Println("key present, value = ", value)
} else {
//key does not exist
fmt.Println("key does not exist")
}
}