Zusammenfassung – Generische Sammlung
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 72 von 107.
Aufgabe
EinfachLass uns eine generische Queue-Datenstruktur erstellen, die alles veranschaulicht, was du über Generics in Go gelernt hast! Im Gegensatz zu einem Stack (LIFO) folgt eine Queue der First-In-First-Out-Reihenfolge (FIFO): Das zuerst hinzugefügte Element wird als Erstes entfernt.
Du organisierst deinen Code auf zwei Dateien:
queue.go: Definiere deine generische Queue-Sammlung.Erstelle eine generische Struktur
Queue[T any], die Elemente intern speichert. Deine Queue soll diese Operationen unterstützen:Enqueue(item T)– fügt ein Element am Ende der Queue hinzuDequeue() (T, bool)– entfernt das Element am Anfang der Queue und gibt es zurück, zusammen mit einem booleschen Wert, der den Erfolg angibt (gib den Nullwert undfalsezurück, wenn die Queue leer ist)Peek() (T, bool)– gibt das Element am Anfang zurück, ohne es zu entfernen (dasselbe Rückgabemuster wie bei Dequeue)Size() int– gibt die Anzahl der Elemente in der Queue zurückIsEmpty() bool– gibt true zurück, wenn die Queue keine Elemente enthält
Erstelle außerdem eine Konstruktorfunktion
NewQueue[T any]() *Queue[T], die einen Zeiger auf eine initialisierte leere Queue zurückgibt.main.go: Veranschauliche deine Queue mit verschiedenen Typen, die auf der Eingabe basieren.Lies einen Typindikator (
intoderstring) ein und anschließend eine Reihe von Befehlen, die auf der Queue ausgeführt werden sollen. Jeder Befehl steht in einer eigenen Zeile:enqueue [value]– fügt den Wert zur Queue hinzudequeue– entfernt das Element am Anfang und gibt es aus (gibemptyaus, wenn die Queue leer ist)peek– gibt das Element am Anfang aus, ohne es zu entfernen (gibemptyaus, wenn die Queue leer ist)size– gibt die aktuelle Größe aus
Lies Befehle ein, bis du
doneerhältst.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Typindikator (
intoderstring) - Folgende Zeilen: Befehle bis zu
done
Zum Beispiel bei folgender Eingabe:
int
enqueue 10
enqueue 20
enqueue 30
peek
dequeue
size
dequeue
dequeue
dequeue
doneDeine Ausgabe sollte wie folgt aussehen:
10
10
2
20
30
emptyUnd bei folgender Eingabe:
string
enqueue hello
enqueue world
size
peek
dequeue
peek
doneDeine Ausgabe sollte wie folgt aussehen:
2
hello
hello
worldDeine Queue sollte für Integer- und String-Typen identisch funktionieren. Dadurch wird veranschaulicht, wie eine einzige generische Implementierung mehrere konkrete Typen verarbeitet und dabei vollständige Typsicherheit gewährleistet.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Lese den Typindikator
scanner.Scan()
typeIndicator := scanner.Text()
if typeIndicator == "int" {
// TODO: Erstelle eine Integer-Warteschlange mit NewQueue[int]()
// Verarbeite Befehle für die Integer-Warteschlange
for scanner.Scan() {
line := scanner.Text()
if line == "done" {
break
}
parts := strings.SplitN(line, " ", 2)
command := parts[0]
// TODO: Behandle Befehle: enqueue, dequeue, peek, size
// Für enqueue den Integer-Wert aus parts[1] parsen
// Für dequeue/peek "empty" ausgeben, wenn die Warteschlange leer ist
_ = command
}
} else if typeIndicator == "string" {
// TODO: Erstelle eine String-Warteschlange mit NewQueue[string]()
// Verarbeite Befehle für die String-Warteschlange
for scanner.Scan() {
line := scanner.Text()
if line == "done" {
break
}
parts := strings.SplitN(line, " ", 2)
command := parts[0]
// TODO: Behandle Befehle: enqueue, dequeue, peek, size
// Für enqueue den String-Wert aus parts[1] verwenden
// Für dequeue/peek "empty" ausgeben, wenn die Warteschlange leer ist
_ = command
}
}
// Diese sind hier, um Fehler durch ungenutzte Imports während der Entwicklung zu vermeiden
_ = strconv.Atoi
_ = fmt.Println
}
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP in Go
Externe DateienGo-Workspace & ModulePackages & ImportsExportierte vs. nicht exportierte NamenEinführung in OOP mit GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktorfunktionenRückblick – Einfacher Taschenrechner4Schnittstellen
Einführung in SchnittstellenImplizite ImplementierungSchnittstelle als VertragLeere Schnittstelle (any)TypzusicherungTypwechselZusammensetzung von SchnittstellenStringer- und Error-SchnittstellenRückblick – Formenrechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf PaketebeneGetter- und Setter-MethodenInformationsverbergung in GoRückblick – Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterTypbeschränkungenGenerische StrukturenWorkaround für generische MethodenZusammenfassung – Generische Sammlung2Typen & Structs im Detail
Grundlegende & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct-TagsAnonyme StructsVerschachtelte StructsNullwerte & StandardwerteRückblick – Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen der Struct-EinbettungMethoden-PromotionMehrere Structs einbettenEinbettung vs. AggregationVerbergen eingebetteter MethodenRückblick – Mitarbeiterhierarchie8Fehlerbehandlung & OOP
Das Error-InterfaceBenutzerdefinierte FehlertypenError-Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverRückblick – Dateiparser3Zeiger & Speicher
Grundlagen von Zeigern in GoZeiger auf StructsÜbergabe per Wert vs. ReferenzDie Funktion new()Garbage Collection in GoRückblick – Verkettete Liste erstellen6Polymorphismus in Go
Polymorphismus über InterfacesDuck-Typing in GoRegeln zur Interface-ErfüllungPolymorphe SammlungenDependency InjectionZusammenfassung – Zahlungsprozessor9Konkurrenz & OOP
Grundlagen der GoroutinesChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignRückblick – Worker PoolÜbe selbstständig: Online-Go-Compiler