Comprendre les cartes en Go

La plupart des langages de programmation modernes ont le concept de typedictionary ouhash. Ces types sont couramment utilisés pour stocker des données par paires avec unkey qui correspond à unvalue.

Dans Go, le type de donnéesmap est ce que la plupart des programmeurs considéreraient comme le typedictionary. Il mappe les clés aux valeurs, en créant des paires clé-valeur qui constituent un moyen utile de stocker des données dans Go. Une carte est construite à l'aide du mot-clémap suivi du type de données clé entre crochets[ ], suivi du type de données valeur. Les paires clé-valeur sont ensuite placées à l'intérieur d'accolades de part et d'autre \ {}:

map[key]value{}

Vous utilisez généralement des cartes dans Go pour conserver des données connexes, telles que les informations contenues dans un ID. Une carte avec des données ressemble à ceci:

map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

Outre les accolades, il existe également des deux points dans la carte qui connectent les paires clé-valeur. Les mots à la gauche des deux points sont les clés. Les clés peuvent être de n'importe quel type decomparable dans Go, commestrings,ints, etc.

Les clés dans l'exemple de carte sont:

  • "name"

  • "animal"

  • "color"

  • "location"

Les mots à la droite des deux points sont les valeurs. Les valeurs peuvent être n'importe quel type de données. Les valeurs dans l'exemple de carte sont:

  • "Sammy"

  • "shark"

  • "blue"

  • "ocean"

Comme les autres types de données, vous pouvez stocker la carte dans une variable et l'imprimer:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
fmt.Println(sammy)

Ce serait votre sortie:

Outputmap[animal:shark color:blue location:ocean name:Sammy]

L'ordre des paires clé-valeur peut avoir été décalé. Dans Go, le type de données de la carte n’est pas ordonné. Quelle que soit l'ordre, les paires clé-valeur resteront intactes, vous permettant d'accéder aux données en fonction de leur signification relationnelle.

Accéder aux éléments de la carte

Vous pouvez appeler les valeurs d'une carte en référençant les clés associées. Comme les cartes offrent des paires clé-valeur pour le stockage de données, elles peuvent constituer des éléments importants et utiles dans votre programme Go.

Si vous souhaitez isoler le nom d’utilisateur de Sammy, vous pouvez le faire en appelantsammy["name"]; la variable contenant votre carte et la clé associée. Imprimons cela:

fmt.Println(sammy["name"])

Et recevez la valeur en sortie:

OutputSammy

Les cartes se comportent comme une base de données. au lieu d'appeler un entier pour obtenir une valeur d'index particulière comme vous le feriez avec une tranche, vous affectez une valeur à une clé et appelez cette clé pour obtenir sa valeur associée.

En appelant la clé"name", vous recevez la valeur de cette clé, qui est"Sammy".

De même, vous pouvez appeler les valeurs restantes dans la cartesammy en utilisant le même format:

fmt.Println(sammy["animal"])
// returns shark

fmt.Println(sammy["color"])
// returns blue

fmt.Println(sammy["location"])
// returns ocean

En utilisant les paires clé-valeur dans les types de données de carte, vous pouvez référencer des clés pour récupérer des valeurs.

Clés et valeurs

Contrairement à certains langages de programmation, Go n'a pas de fonctionsconvenience pour lister les clés ou les valeurs d'une carte. Un exemple de cela serait la méthode.keys() de Python pour les dictionnaires. Il permet cependant une itération en utilisant l'opérateurrange:

for key, value := range sammy {
    fmt.Printf("%q is the key for the value %q\n", key, value)
}

Lorsque vous parcourez une carte dans Go, deux valeurs sont renvoyées. La première valeur sera la clé et la deuxième valeur sera la valeur. Go créera ces variables avec le type de données correct. Dans ce cas, la clé de mappage était unstring donckey sera également une chaîne. Levalue est également une chaîne:

Output"animal" is the key for the value "shark"
"color" is the key for the value "blue"
"location" is the key for the value "ocean"
"name" is the key for the value "Sammy"

Pour obtenir une liste des seules touches, vous pouvez à nouveau utiliser l'opérateur de plage. Vous pouvez déclarer qu'une seule variable pour accéder uniquement aux clés:

keys := []string{}

for key := range sammy {
    keys = append(keys, key)
}
fmt.Printf("%q", keys)

Le programme commence par déclarer une tranche pour stocker vos clés.

La sortie ne montrera que les clés de votre carte:

Output["color" "location" "name" "animal"]

Encore une fois, les clés ne sont pas triées. Si vous souhaitez les trier, vous utilisez la fonctionsort.Strings du packagesort:

sort.Strings(keys)

Avec cette fonction, vous recevrez le résultat suivant:

Output["animal" "color" "location" "name"]

Vous pouvez utiliser le même modèle pour extraire uniquement les valeurs d'une carte. Dans l'exemple suivant, vous pré-allouez la tranche pour éviter les allocations, ce qui rend le programme plus efficace:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

items := make([]string, len(sammy))

var i int

for _, v := range sammy {
    items[i] = v
    i++
}
fmt.Printf("%q", items)

D'abord, vous déclarez une tranche pour stocker vos clés; Puisque vous connaissez le nombre d'éléments dont vous avez besoin, vous pouvez éviter les allocations de mémoire potentielles en définissant la tranche avec exactement la même taille. Vous déclarez ensuite votre variable d'index. Comme vous ne voulez pas de clé, vous utilisez l’opérateur_, lors du démarrage de votre boucle, pour ignorer la valeur de la clé. Votre sortie serait la suivante:

Output["ocean" "Sammy" "shark" "blue"]

Pour déterminer le nombre d'éléments dans une carte, vous pouvez utiliser la fonctionlen intégrée:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}
fmt.Println(len(sammy))

La sortie affiche le nombre d'éléments de votre carte:

Output4

Bien que Go ne soit pas livré avec des fonctions pratiques pour obtenir des clés et des valeurs, quelques lignes de code suffisent pour récupérer les clés et les valeurs en cas de besoin.

Vérifier l'existence

Maps in Go renvoie la valeur zéro pour le type de valeur de la carte lorsque la clé demandée est manquante. Pour cette raison, vous avez besoin d'un autre moyen de différencier un zéro stocké d'une clé manquante.

Examinons une valeur dans une carte que vous savez inexistante et examinons la valeur renvoyée:

counts := map[string]int{}
fmt.Println(counts["sammy"])

Vous verrez le résultat suivant:

Output0

Même si la clésammy n'était pas dans la carte, Go a quand même renvoyé la valeur de0. Cela est dû au fait que le type de données de valeur est unint, et comme Go a une valeur zéro pour toutes les variables, il renvoie la valeur zéro de0.

Dans de nombreux cas, cela n'est pas souhaitable et entraînerait un bogue dans votre programme. Lors de la recherche de la valeur dans une carte, Go peut renvoyer une seconde valeur deoptional. Cette deuxième valeur est unbool et seratrue si la clé a été trouvée, oufalse si la clé n'a pas été trouvée. Dans Go, c'est ce qu'on appelle l'idiomeok. Même si vous pouvez nommer la variable qui capture le deuxième argument comme vous le souhaitez, dans Go, vous la nommez toujoursok:

count, ok := counts["sammy"]

Si la clésammy existe dans la cartecounts, alorsok seratrue. Sinon,ok sera faux.

Vous pouvez utiliser la variableok pour décider quoi faire dans votre programme:

if ok {
    fmt.Printf("Sammy has a count of %d\n", count)
} else {
    fmt.Println("Sammy was not found")
}

Cela donnerait la sortie suivante:

OutputSammy was not found

Dans Go, vous pouvez combiner la déclaration de variable et la vérification conditionnelle avec un bloc if / else. Cela vous permet d'utiliser une seule déclaration pour cette vérification:

if count, ok := counts["sammy"]; ok {
    fmt.Printf("Sammy has a count of %d\n", count)
} else {
    fmt.Println("Sammy was not found")
}

Lorsque vous récupérez une valeur d’une carte dans Go, il est toujours bon de vérifier son existence afin d’éviter les bogues dans votre programme.

Modification de cartes

Les cartes sont une structure de données modifiable, vous pouvez donc les modifier. Voyons comment ajouter et supprimer des éléments de carte dans cette section.

Ajout et modification d'éléments de carte

Sans utiliser de méthode ou de fonction, vous pouvez ajouter des paires clé-valeur aux mappes. Pour ce faire, utilisez le nom de la variable maps, suivi de la valeur de clé entre crochets[ ], et utilisez l'opérateur equal= pour définir une nouvelle valeur:

map[key] = value

En pratique, vous pouvez voir ce travail en ajoutant une paire clé-valeur à une carte appeléeusernames:

usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}

usernames["Drew"] = "squidly"
fmt.Println(usernames)

La sortie affichera la nouvelle paire clé-valeurDrew:squidly dans la carte:

Outputmap[Drew:squidly Jamie:mantisshrimp54 Sammy:sammy-shark]

Comme les cartes sont retournées sans ordre, cette paire peut apparaître n'importe où dans la sortie de carte. Si vous utilisez la mappeusernames plus tard dans votre fichier programme, elle inclura la paire clé-valeur supplémentaire.

Vous pouvez également utiliser cette syntaxe pour modifier la valeur attribuée à une clé. Dans ce cas, vous référencez une clé existante et lui transmettez une valeur différente.

Considérons une carte appeléefollowers qui suit les abonnés des utilisateurs sur un réseau donné. L'utilisateur"drew" a eu une augmentation du nombre de followers aujourd'hui, vous devez donc mettre à jour la valeur entière transmise à la clé"drew". Vous allez utiliser la fonctionPrintln() pour vérifier que la carte a été modifiée:

followers := map[string]int{"drew": 305, "mary": 428, "cindy": 918}
followers["drew"] = 342
fmt.Println(followers)

Votre sortie affichera la valeur mise à jour pourdrew:

Outputmap[cindy:918 drew:342 mary:428]

Vous voyez que le nombre d'adeptes est passé de la valeur entière de305 à342.

Vous pouvez utiliser cette méthode pour ajouter des paires clé-valeur aux mappes avec une entrée utilisateur. Écrivons un programme rapide appeléusernames.go qui s'exécute sur la ligne de commande et permet à l'utilisateur d'ajouter plus de noms et de noms d'utilisateurs associés:

usernames.go

package main

import (
    "fmt"
    "strings"
)

func main() {
    usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}

    for {
        fmt.Println("Enter a name:")

        var name string
        _, err := fmt.Scanln(&name)

        if err != nil {
            panic(err)
        }

        name = strings.TrimSpace(name)

        if u, ok := usernames[name]; ok {
            fmt.Printf("%q is the username of %q\n", u, name)
            continue
        }

        fmt.Printf("I don't have %v's username, what is it?\n", name)

        var username string
        _, err = fmt.Scanln(&username)

        if err != nil {
            panic(err)
        }

        username = strings.TrimSpace(username)

        usernames[name] = username

        fmt.Println("Data updated.")
    }
}

Dansusernames.go, vous définissez d'abord la carte d'origine. Vous configurez ensuite une boucle pour parcourir les noms. Vous demandez à votre utilisateur de saisir un nom et de déclarer une variable dans laquelle le stocker. Ensuite, vous vérifiez si vous avez eu une erreur; si c'est le cas, le programme se terminera avec unpanic. PuisqueScanln capture toute l'entrée, y compris le retour chariot, vous devez supprimer tout espace de l'entrée; vous faites cela avec la fonctionstrings.TrimSpace.

Le blocif vérifie si le nom est présent dans la carte et imprime les commentaires. Si le nom est présent, il retourne ensuite en haut de la boucle. Si le nom ne figure pas sur la carte, il fournit des informations à l'utilisateur, puis vous demande un nouveau nom d'utilisateur pour le nom associé. Le programme vérifie à nouveau s'il y a une erreur. En l'absence d'erreur, il élimine le retour chariot, attribue la valeur de nom d'utilisateur à la clé de nom, puis imprime le retour d'informations indiquant que les données ont été mises à jour.

Lançons le programme en ligne de commande:

go run usernames.go

Vous verrez le résultat suivant:

OutputEnter a name:
Sammy
"sammy-shark" is the username of "Sammy"
Enter a name:
Jesse
I don't have Jesse's username, what is it?
JOctopus
Data updated.
Enter a name:

Lorsque vous avez terminé les tests, appuyez surCTRL + C pour quitter le programme.

Cela montre comment vous pouvez modifier les cartes de manière interactive. Avec ce programme particulier, dès que vous quittez le programme avecCTRL + C, vous perdrez toutes vos données à moins que vous n'implémentiez un moyen de gérer la lecture et l'écriture de fichiers.

Pour résumer, vous pouvez ajouter des éléments aux cartes ou modifier les valeurs avec la syntaxemap[key] = value.

Suppression d'éléments de carte

Tout comme vous pouvez ajouter des paires clé-valeur et modifier des valeurs dans le type de données de la carte, vous pouvez également supprimer des éléments dans une carte.

Pour supprimer une paire clé-valeur d'une carte, vous pouvez utiliser la fonction intégréedelete(). Le premier argument est la carte que vous supprimez. Le deuxième argument est la clé que vous supprimez:

delete(map, key)

Définissons une carte des autorisations:

permissions := map[int]string{1: "read", 2: "write", 4: "delete", 8: "create", 16:"modify"}

Vous n’avez plus besoin de l’autorisationmodify, vous allez donc la supprimer de votre carte. Ensuite, vous imprimerez la carte pour confirmer qu’elle a été supprimée:

permissions := map[int]string{1: "read", 2: "write", 4: "delete", 8: "create", 16: "modify"}
delete(permissions, 16)
fmt.Println(permissions)

La sortie confirmera la suppression:

Outputmap[1:read 2:write 4:delete 8:create]

La lignedelete(permissions, 16) supprime la paire clé-valeur16:"modify" de la cartepermissions.

Si vous souhaitez effacer une carte de toutes ses valeurs, vous pouvez le faire en la rendant égale à une carte vide du même type. Cela créera une nouvelle carte vide à utiliser et l'ancienne carte sera effacée de la mémoire par le ramasse-miettes.

Supprimons tous les éléments de la cartepermissions:

permissions = map[int]string{}
fmt.Println(permissions)

La sortie montre que vous avez maintenant une carte vide dépourvue de paires clé-valeur:

Outputmap[]

Comme les cartes sont des types de données modifiables, elles peuvent être ajoutées, modifiées et avoir des éléments supprimés et effacés.

Conclusion

Ce tutoriel a exploré la structure des données de la carte dans Go. Les cartes sont constituées de paires clé-valeur et permettent de stocker des données sans recourir à l'indexation. Cela nous permet de récupérer des valeurs en fonction de leur signification et de leur relation avec d'autres types de données.