Pointer als Map-Werte
Teil des Abschnitts Logik & Ablauf der GO-Journey von Coddy. Lektion 27 von 68.
Während das direkte Speichern von Strukturen in Maps nützlich ist, eröffnet das Speichern von Zeigern auf Strukturen eine leistungsstarke Möglichkeit: die Originaldaten der Struktur direkt über die Map zu ändern. Dieser Ansatz ist unverzichtbar, wenn du deine Daten aktualisieren musst, nachdem sie gespeichert wurden.
Wenn du einen Zeiger auf eine Struktur als Kartenwert speicherst, speicherst du die Speicheradresse der Struktur und nicht deren Kopie. So deklarierst du eine solche Karte und arbeitest mit ihr:
type Product struct {
Price float64
Quantity int
}
products := map[string]*Product{
"laptop": &Product{Price: 999.99, Quantity: 5},
"mouse": &Product{Price: 25.50, Quantity: 20},
}Der entscheidende Vorteil wird deutlich, wenn du die Daten ändern musst. Da du mit Zeigern arbeitest, wirken sich Änderungen über die map auf die ursprüngliche Struktur aus:
// Aktualisiere den Preis des Laptops direkt über die Map
products["laptop"].Price = 899.99
fmt.Println(products["laptop"].Price) // gibt aus: 899.99Dieses Muster ist besonders wertvoll in Anwendungen, in denen du gespeicherte Daten häufig aktualisieren musst, beispielsweise in Bestandsverwaltungssystemen, Benutzerprofilen oder jedem Szenario, in dem die Map als dein primärer Datenspeicher dient und Änderungen dauerhaft gespeichert werden müssen.
Aufgabe
EinfachErstelle ein einfaches Bestandsverwaltungssystem, das die Leistungsfähigkeit der Verwendung von Zeigern auf Structs als Map-Werte demonstriert. Diese Herausforderung zeigt, wie pointerbasierte Maps die direkte Änderung gespeicherter Daten ermöglichen und dein Bestandssystem dadurch effizient und reaktionsfähig gegenüber Aktualisierungen wird.
Du erhältst drei Eingaben:
- Eine Zeichenkette, die die Anzahl der Produkte darstellt (z. B.
"4") - Eine Zeichenkette mit Produktdaten im Format:
"name1:price1:quantity1,name2:price2:quantity2,name3:price3:quantity3"(z. B."laptop:999.99:5,mouse:25.50:20,keyboard:75.00:15,monitor:299.99:8") - Eine Zeichenkette mit Aktualisierungsvorgängen im Format:
"operation1:product1:value1,operation2:product2:value2", wobei die Vorgänge entweder"price"oder"quantity"sind (z. B."price:laptop:899.99,quantity:mouse:25,price:keyboard:65.00")
Deine Aufgabe ist:
- Definiere ein
Product-Struct mit den folgenden Feldern:Price(float64) – der Preis des ProduktsQuantity(int) – die Lagermenge des Produkts
- Erstelle eine Map, deren Schlüssel Produktnamen (Zeichenketten) und deren Werte Zeiger auf
Product-Structs sind - Verarbeite die Produktdaten aus der zweiten Eingabe:
- Teile die Eingabe anhand von Kommas auf, um einzelne Produkteinträge zu erhalten
- Teile jeden Eintrag anhand von Doppelpunkten auf, um Name, Preis und Menge zu trennen
- Wandle die Preiszeichenkette in einen float64 und die Mengenzeichenkette in eine Ganzzahl um
- Erstelle ein
Product-Struct und speichere einen Zeiger darauf in der Map
- Speichere die Produktnamen während der Verarbeitung zusätzlich in einem separaten Slice – in der Reihenfolge, in der sie in der Eingabe vorkommen. Das Durchlaufen einer Map in Go besucht die Schlüssel in zufälliger Reihenfolge, daher sorgt das Slice dafür, dass jede Auflistung in der Reihenfolge der Eingabe bleibt.
- Gib den anfänglichen Bestand mit dem Header
"Initial Inventory:"aus - Zeige jedes Produkt im Format:
"[name]: $[price] (Stock: [quantity])" - Verarbeite die Aktualisierungsvorgänge aus der dritten Eingabe und wende sie an:
- Teile die Eingabe anhand von Kommas auf, um einzelne Vorgänge zu erhalten
- Teile jeden Vorgang anhand von Doppelpunkten auf, um Vorgangstyp, Produktname und neuen Wert zu erhalten
- Aktualisiere das entsprechende Feld direkt über den Map-Zeiger
- Gib jede Aktualisierung im Format aus:
"Updated [product]: [field] changed to [new_value]"
- Gib den aktualisierten Bestand mit dem Header
"Updated Inventory:"aus - Zeige jedes Produkt erneut im selben Format wie bei der anfänglichen Anzeige
- Berechne den Gesamtwert des Bestands und gib ihn aus:
"Total Inventory Value: $[total_value]"
Verwende das Paket strconv, um Preis- und Mengenzeichenketten in ihre jeweiligen numerischen Typen umzuwandeln. Formatiere bei der Anzeige alle Preise mit 2 Dezimalstellen. Diese Herausforderung zeigt, wie das Speichern von Zeigern in Maps ermöglicht, die Daten des ursprünglichen Structs direkt zu ändern, sodass deine Bestandsaktualisierungen sofort und dauerhaft übernommen werden, ohne Werte der Map erneut zuweisen zu müssen.
Probier es selbst
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
// Eingabe lesen
var numProductsStr string
var productDataStr string
var operationsStr string
fmt.Scanln(&numProductsStr)
fmt.Scanln(&productDataStr)
fmt.Scanln(&operationsStr)
// TODO: Product-Struct hier definieren
// TODO: Map erstellen, um Produkt-Zeiger zu speichern
// TODO: Slice erstellen, um die Produktreihenfolge beizubehalten (um konsistente Ausgabe sicherzustellen)
// TODO: Produktdaten parsen und die Map befüllen
// Denk daran:
// - productDataStr anhand von Kommas aufteilen, um einzelne Einträge zu erhalten
// - Für jeden Eintrag anhand von Doppelpunkten aufteilen, um name, price, quantity zu erhalten
// - price- und quantity-Strings in passende Typen umwandeln
// - Zeiger auf Product-Struct in der Map speichern
// - Produktname zum order-Slice hinzufügen
// TODO: Display initial inventory
// Verwende den order-Slice, um konsistent durch die Produkte zu iterieren
// Format: "[name]: $[price] (Stock: [quantity])"
// TODO: Aktualisierungsoperationen parsen und anwenden
// Denk daran:
// - operationsStr anhand von Kommas aufteilen, um einzelne Operationen zu erhalten
// - Für jede Operation anhand von Doppelpunkten aufteilen, um type, name, value zu erhalten
// - Das entsprechende Feld direkt über den Map-Zeiger aktualisieren
// - Aktualisierungsnachricht für jede Operation ausgeben
// TODO: Display updated inventory
// Erneut die order-Slice für konsistente Ausgabe verwenden
// Gesamtwert während der Anzeige berechnen
// TODO: Calculate and display total inventory value
// Format: "Total Inventory Value: $[total_value]"
}Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Logik & Ablauf
1Fortgeschrittener Kontrollfluss
Switch mit `fallthrough`Abbrechen von verschachtelten SchleifenFortsetzen einer bestimmten SchleifeDie `goto`-AnweisungZusammenfassung – Fortgeschrittene Schleifensteuerung4Projekt: Einfache Aufgabenliste
Projekt-SetupEine Aufgabe hinzufügen2Structs und Methoden
Methoden für Structs definierenValue ReceiverPointer ReceiverReceiver auswählenMethoden vs. FunktionenZusammenfassung – Struct-Verhalten5Maps im Detail
Maps von StructsPointer als Map-WertePrüfen auf Nil-MapsMaps vergleichenZusammenfassung – Wortfrequenz-Zähler8Projekt: Einfache Bestandsverwaltung
ProjektübersichtLagerbestand prüfen11Abschlussherausforderungen
Einfache KontaktlisteEinfacher Zahlen-ValidatorSammler für eindeutige Elemente3Interfaces (Die Grundlagen)
Was ist ein Interface?Ein Interface definierenEin Interface implementierenInterface-Typen verwendenLeeres InterfaceType AssertionsType SwitchZusammenfassung – Formen und VerhaltenÜbe selbstständig: Online-Go-Compiler