Heim >Backend-Entwicklung >Golang >Karten in Go
Go enthält einen nativen Typ namens Map, der Hash-Tabellen implementiert. Es handelt sich um einen Datentyp, der aus einer Sammlung eindeutiger Schlüssel und einer Sammlung von Werten für jeden dieser Schlüssel besteht.
Es kann beispielsweise mit einem Wörterbuch in anderen Sprachen verglichen werden, das Schlüssel-Wert-Paare speichert. Auf diese Werte wird mithilfe von Schlüsseln zugegriffen, genau wie bei Arrays und Slices, wie wir im vorherigen Beitrag gesehen haben.
Die Indizes sind nicht auf eine Zahl beschränkt wie in Arrays oder Slices und die Elemente sind nicht geordnet. Wenn wir also eine Karte drucken, wird sie eine zufällige Reihenfolge zurückgeben, wenn wir nichts unternehmen, um den Druck zu überschreiben und die gewünschte Reihenfolge zu erzwingen.
Um eine Karte zu deklarieren, erfolgt dies mit „map[key]value“, wobei „key“ der Typ ist, den unser Schlüssel haben soll (er muss von einem vergleichbaren Typ sein https://go.dev/ref/spec#Comparison_operators). ) und value wird der Typ sein, in dem die Karte in jedem der Schlüssel gespeichert werden soll, egal um welchen Typ es sich handelt, von einem Int bis zu einer Struktur oder einer anderen Karte, was auch immer wir wollen.
Wie bei Slices sind Karten referenzierte Typen, was bedeutet, dass der Nullwert einer Karte Null ist.
Dies geschieht, weil sich darunter eine Hash-Tabelle befindet, in der die Schlüssel und Werte gespeichert sind, und sie lediglich eine Hülle, eine Abstraktion davon sind.
Wenn wir es als Folgendes deklarieren:
var m map[int]int
sein Wert wird Null sein.
Wenn wir möchten, dass es einen Nullwert hat, können wir die Deklaration verwenden:
m := map[int]int{}
Und wir können es sogar genau wie die Slices initialisieren, indem wir die Make-Funktion verwenden.
m := make(map[string]string)
Dadurch wird eine Hash-Map mit dem entsprechenden Speicherpool initialisiert und somit eine Karte zurückgegeben, die auf diese Datenstruktur verweist.
Das Hinzufügen von Werten zu einer Karte erfolgt durch die Verwendung von geschweiften Klammern [] und der geschweiften Klammer, genau wie bei Arrays oder Slices. In diesem Beispiel erstellen wir eine Karte mit den Schlüsseln als Zeichenfolgen und den Werten als Ganzzahlen, um Namen und Alter zu speichern.
ages := make(map[string]int) ages["John"] = 33 ages["Charly"] = 27 ages["Jenny"] = 45 ages["Lisa"] = 19
Wenn wir beim Deklarieren der Karte die Werte hinzufügen möchten, können wir die Kurzdeklaration verwenden und alles im selben Schritt erledigen:
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19}
Um die Werte zu lesen, müssen wir lediglich den Schlüssel zu unserer Karte angeben und sie wird diesen Wert zurückgeben. Um zum Beispiel Lisas Alter herauszufinden, können wir Folgendes tun:
fmt.Println(ages["Lisa"]) // 19
Wenn wir versuchen, auf einen Schlüssel zuzugreifen, der nicht existiert, ist der erhaltene Wert der Nullwert des Typs, in diesem Fall wäre es „“, da es sich um eine Zeichenfolge handelt.
Um zu überprüfen, ob ein Element in der Karte vorhanden ist, können wir prüfen, ob der Typ der Standardtyp ist. Dies ist jedoch nicht sehr zuverlässig, da es möglicherweise vorhanden ist, sein Wert jedoch ein leerer String oder 0 im Fall von int ist , was mit seinem Nullwert übereinstimmen würde, also hilft uns Go bei Folgendem:
val, ok := ages["Randy"]
Wenn wir die Karte mit zwei Werten gleichsetzen, ist der erste der Wert des Elements, auf das über den Schlüssel zugegriffen wird, in diesem Fall „Randy“, der nicht existiert, und der zweite ist ein boolescher Wert, der angibt, ob dies der Fall ist existiert oder nicht.
Wenn uns der Wert nicht interessiert und wir lediglich prüfen möchten, ob ein Schlüssel vorhanden ist, können wir den Wert mit _ wie folgt ignorieren:
_, ok := ages["Randy"]
Wie bei Arrays und Slices können wir die len-Funktion verwenden, um herauszufinden, wie viele Elemente es in der Karte gibt.
fmt.Println(len(ages)) // 4
Wenn wir einen Wert ändern möchten, müssen wir lediglich mit einem Schlüssel auf den Wert zugreifen und ihn mit einem anderen abgleichen, und er wird geändert.
Wenn wir eine zweite Karte deklarieren, die auf die erste zeigt, und wir den Wert der zweiten Karte ändern, da es sich um einen referenzierten Typ handelt, ändern wir den Wert der ersten, da beide darunter dieselbe Hash-Tabelle verwenden.
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19} agesNew := ages agesNew["Bryan"] = 77 fmt.Println(agesNew) // map[Bryan:77 Charly:27 Jenny:45 John:33 Lisa:19] fmt.Println(ages) // map[Bryan:77 Charly:27 Jenny:45 John:33 Lisa:19]
Um Elemente aus einer Karte zu löschen, stellt uns Go eine Löschfunktion mit der folgenden Signatur delete(m map[Type]Type1, key Type) zur Verfügung, die eine Karte und den zu löschenden Schlüssel empfängt.
Wenn wir im vorherigen Fall „Lisa“ eliminieren wollten, würden wir Folgendes tun:
delete(ages, "Lisa")
Wenn wir den Inhalt einer Karte durchgehen möchten, können wir dies mit einem for mit der Variation des Bereichs tun, die wir bereits im Beitrag zu Arrays und Slices gesehen haben.
Dann ist das erste Element der Index, also der Schlüssel, und das zweite der Wert.
for key, value := range ages { fmt.Printf("%s: %d\n", key, value) } // Output: // Jenny: 45 // Lisa: 19 // John: 33 // Charly: 27
Wenn uns wie bei Arrays und Slices nur der Wert interessiert, ohne den Schlüssel, können wir ihn weglassen, indem wir _ verwenden.
for _, value := range ages { fmt.Println(value) } // Output: // 19 // 33 // 27 // 45
Und wenn uns nur der Schlüssel interessiert, können wir den Bereich einer einzelnen Variablen zuweisen, um ihn zu erhalten:
for key := range ages { fmt.Println(key) } // Output: // John // Charly // Jenny // Lisa
As I mentioned in the introduction, in a map the information is not ordered, so when looping through it we cannot specify what order it follows, nor can Go guarantee that the order between executions is the same.
As we saw with arrays and slices, in the standard library there is a sort package which helps us sort elements: https://pkg.go.dev/sort
Following our example with ages and using sort, we can sort the keys of the map before traversing it and thus guarantee that it will be accessed in order.
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19} keys := make([]string, 0, len(ages)) for k := range ages { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Println(k, ages[k]) } // Output: // Charly 27 // Jenny 45 // John 33 // Lisa 19
We declare our ages map with the short declaration as we saw before.
We create a string slices to store the keys and use the make method with 0 length, since we do not have any keys at the moment, but we do reserve the capacity it will have using the len method for the length of our map.
We go through the ages map to keep its keys and add them to the created slice.
We sort the keys alphabetically with the sort.Strings function.
We go through the slice of keys, already ordered, and access the map with the key in question.
This way we will access the map in an orderly manner and we can do the logic that our program needs.
Something to keep in mind with maps is that they are not safe to use concurrently. If these are concurrent reads, either accessing a value or through a for with a range, there is no problem with multiple goroutines accessing it at the same time.
The problematic case is when you want to update the value of a map concurrently, either by adding or removing elements from it, and at the same time you are reading it from another side, for example.
To solve this situation there are several possible solutions, which I will not go into much detail, I will simply mention and leave it to your choice to delve deeper into them.
If we use the sync package: https://pkg.go.dev/sync from the standard library, we can control the synchrony between the different goroutines.
A possible use is the RWMutex type which allows us to lock and unlock reads and writes to a type. So if we have a type that contains a sync.RWMutex and a map we can control when it can be accessed.
Another interesting type to investigate within the same sync package is Map, which already offers us a series of functions that will help us work with our map, which in the end we will not be able to work with natively, as with the previous solution.
Depending on the use case we are implementing, one or the other will be more useful to us, and there is no one better than the other, it will always depend on what we need.
I hope everything that I have tried to explain in this post has been clear, and please if there is any part that has not been completely clear or there are parts that I have not covered that you would like me to do, leave me a comment right here or through my social networks that you have on my profile and I will be happy to respond.
Das obige ist der detaillierte Inhalt vonKarten in Go. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!