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


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow