Recherche…
Introduction
Les cartes sont des types de données utilisés pour stocker des paires clé-valeur non ordonnées, de sorte que rechercher la valeur associée à une clé donnée est très efficace. Les clés sont uniques. La structure de données sous-jacente se développe au besoin pour accueillir de nouveaux éléments, de sorte que le programmeur n'a pas besoin de s'inquiéter de la gestion de la mémoire. Ils sont similaires à ce que d'autres langages appellent des tables de hachage, des dictionnaires ou des tableaux associatifs.
Syntaxe
- var mapName map [KeyType] ValueType // déclare une carte
- var mapName = map [KeyType] ValueType {} // déclare et attribue une carte vide
- var mapName = map [KeyType] ValueType {key1: val1, key2: val2} // déclare et attribue une carte
- mapName: = make (mappe [KeyType] ValueType) // déclare et initialise la carte de taille par défaut
- mapName: = make (mappe [KeyType] ValueType, longueur) // déclare et initialise la carte de taille de longueur
- mapName: = map [KeyType] ValueType {} // déclare automatiquement et attribue une map vide avec: =
- mapName: = map [KeyType] ValueType {key1: value1, key2: value2} // déclare automatiquement et assigne une carte avec: =
- value: = mapName [clé] // Récupère la valeur par clé
- value, hasKey: = mapName [clé] // Récupère la valeur par clé, 'hasKey' est 'true' si la clé existe dans la carte
- mapName [clé] = valeur // Définir la valeur par clé
Remarques
Go fournit un type de map
intégré qui implémente une table de hachage . Les cartes sont le type de données associatif intégré de Go (également appelé hachage ou dictionnaires dans d'autres langues).
Déclarer et initialiser une carte
Vous définissez une carte à l'aide du mot-clé map
, suivi des types de ses clés et de ses valeurs:
// 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
Les cartes sont des types de référence et, une fois définies, elles ont une valeur nil
. Écrit sur des cartes nulles paniquera et les lectures renverront toujours la valeur zéro.
Pour initialiser une carte, utilisez la fonction make
:
m := make(map[string]int)
Avec la forme de make
deux paramètres, il est possible de spécifier une capacité d'entrée initiale pour la carte, en remplaçant la capacité par défaut:
m := make(map[string]int, 30)
Alternativement, vous pouvez déclarer une carte, l'initialiser à sa valeur zéro, puis lui attribuer une valeur littérale plus tard, ce qui aide si vous regroupez la structure en json, produisant ainsi une carte vide au retour.
m := make(map[string]int, 0)
Vous pouvez également créer une carte et définir sa valeur initiale entre accolades ( {}
).
var m map[string]int = map[string]int{"Foo": 20, "Bar": 30}
fmt.Println(m["Foo"]) // outputs 20
Toutes les instructions suivantes entraînent la liaison de la variable à la même valeur.
// 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{}
Nous pouvons également utiliser un littéral de carte pour créer une nouvelle carte avec des paires clé / valeur initiales .
Le type de clé peut être de tout type comparable ; Cela exclut notamment les fonctions, les cartes et les tranches . Le type de valeur peut être n'importe quel type, y compris les types personnalisés ou 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{}
Créer une carte
On peut déclarer et initialiser une carte dans une seule instruction en utilisant un littéral composite .
Utilisation du type automatique Déclaration de variable courte:
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"}
Le même code, mais avec des types de variables:
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"}
Vous pouvez également inclure vos propres structures dans une carte:
Vous pouvez utiliser des types personnalisés comme valeur:
// 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"}}
Votre struct peut également être la clé de la carte:
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}
Vous pouvez créer une carte vide simplement en ne saisissant aucune valeur entre crochets {}
.
mapIntInt := map[int]int{}
mapIntString := map[int]string{}
mapStringInt := map[string]int{}
mapStringString := map[string]string{}
mapStringPerson := map[string]Person{}
Vous pouvez créer et utiliser une carte directement sans avoir à l'assigner à une variable. Cependant, vous devrez spécifier la déclaration et le contenu.
// 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)
Valeur zéro d'une carte
La valeur zéro d'une map
est nil
et a une longueur de 0
.
var m map[string]string
fmt.Println(m == nil) // true
fmt.Println(len(m) ==0) // true
Une carte nil
n'a pas de clé et les clés ne peuvent pas être ajoutées. Une carte nil
se comporte comme une carte vide si elle est lue mais provoque une panique à l'exécution si elle est écrite.
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
Vous ne devriez pas essayer de lire ou d'écrire sur une carte de valeur zéro. Au lieu de cela, initialisez la carte (avec make
ou affectation) avant de l'utiliser.
var m map[string]string
m = make(map[string]string) // OR m = map[string]string{}
m["foo"] = "bar"
Itérer les éléments d'une carte
import fmt
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, value := range people {
fmt.Println("Name:", key, "Age:", value)
}
Notez que lors d'une itération sur une carte avec une boucle d'intervalle, l'ordre d'itération n'est pas spécifié et n'est pas garanti pour être identique d'une itération à l'autre.
Vous pouvez également ignorer les clés ou les valeurs de la carte, si vous souhaitez simplement saisir des touches ou saisir des valeurs.
Itérer les clés d'une carte
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, _ := range people {
fmt.Println("Name:", key)
}
Si vous cherchez simplement les clés, car elles sont la première valeur, vous pouvez simplement déposer le trait de soulignement:
for key := range people {
fmt.Println("Name:", key)
}
Notez que lors d'une itération sur une carte avec une boucle d'intervalle, l'ordre d'itération n'est pas spécifié et n'est pas garanti pour être identique d'une itération à l'autre.
Supprimer un élément de carte
La delete
fonction intégrée supprime l'élément avec la clé spécifiée sur une carte.
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]
Si la map
est nil
ou qu’il n’ya pas d’élément de ce type, delete
n’a aucun effet.
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
Compter les éléments de la carte
La fonction intégrée len
renvoie le nombre d'éléments dans une map
m := map[string]int{}
len(m) // 0
m["foo"] = 1
len(m) // 1
Si une variable pointe vers une carte nil
, alors len
renvoie 0.
var m map[string]int
len(m) // 0
Accès simultané aux cartes
Les cartes in go ne sont pas sûres pour la concurrence. Vous devez prendre un verrou pour lire et écrire dessus si vous y accédez simultanément. Généralement, la meilleure option consiste à utiliser sync.RWMutex
car vous pouvez avoir des verrous en lecture et en écriture. Cependant, un sync.Mutex
pourrait également être utilisé.
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")
}
Le compromis entre les fonctions d'encapsulation se situe entre l'accès public de la carte sous-jacente et l'utilisation correcte des verrous appropriés.
Création de cartes avec des tranches en tant que valeurs
m := make(map[string][]int)
L'accès à une clé inexistante renverra une tranche nulle en tant que valeur. Puisque les tranches nuls agissent comme des tranches de longueur zéro lorsqu'elles sont utilisées avec append
ou d'autres fonctions intégrées, vous n'avez normalement pas besoin de vérifier si une clé existe:
// m["key1"] == nil && len(m["key1"]) == 0
m["key1"] = append(m["key1"], 1)
// len(m["key1"]) == 1
La suppression d'une clé de la carte ramène la clé à une tranche nulle:
delete(m, "key1")
// m["key1"] == nil
Vérifier l'élément dans une carte
Pour obtenir une valeur de la carte, il suffit de faire quelque chose comme: 00
value := mapName[ key ]
Si la carte contient la clé, elle renvoie la valeur correspondante.
Sinon, il renvoie la valeur zéro du type de valeur de la carte ( 0
si la carte des valeurs int
, ""
si la carte des valeurs de 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
Pour différencier les valeurs vides des clés inexistantes, vous pouvez utiliser la seconde valeur renvoyée de l’accès à la carte (en utilisant la value, hasKey := map["key"]
like value, hasKey := map["key"]
).
Cette seconde valeur est boolean
et sera:
-
true
lorsque la valeur est dans la carte, -
false
lorsque la carte ne contient pas la clé donnée.
Regardez l'exemple suivant:
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
}
Itérer les valeurs d'une carte
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for _, value := range people {
fmt.Println("Age:", value)
}
Notez que lors d'une itération sur une carte avec une boucle d'intervalle, l'ordre d'itération n'est pas spécifié et n'est pas garanti pour être identique d'une itération à l'autre.
Copier une carte
Comme les tranches, les cartes contiennent des références à une structure de données sous-jacente. Donc, en assignant sa valeur à une autre variable, seule la référence sera transmise. Pour copier la carte, il est nécessaire de créer une autre carte et de copier chaque valeur:
// 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
}
Utiliser une carte comme un ensemble
Certaines langues ont une structure native pour les ensembles. Pour créer un ensemble dans Go, il est recommandé d'utiliser une carte du type valeur de l'ensemble dans une structure vide ( map[Type]struct{}
).
Par exemple, avec des chaînes:
// 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")
}