sort.Interface
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 74 von 107.
Das Paket sort bietet ein weiteres hervorragendes Beispiel für schnittstellenbasiertes Design. Um eine benutzerdefinierte Sammlung zu sortieren, muss dein Typ sort.Interface implementieren:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}Diese drei Methoden liefern dem Sortieralgorithmus alles, was er benötigt: die Länge der collection, eine Möglichkeit, elements zu vergleichen, und eine Möglichkeit, sie zu vertauschen. So machst du einen Slice aus benutzerdefinierten Structs sortierbar:
type Person struct {
Name string
Age int
}
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func main() {
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Carol", 35},
}
sort.Sort(ByAge(people))
fmt.Println(people)
// [{Bob 25} {Alice 30} {Carol 35}]
}Die entscheidende Erkenntnis besteht darin, einen benannten Typ (ByAge) auf Grundlage deines Slices zu erstellen. Dadurch kannst du für dieselben Daten unterschiedliche Sortierverhalten definieren. Du könntest stattdessen ByName mit einer anderen Implementierung von Less erstellen, um alphabetisch zu sortieren.
Sobald dein Typ sort.Interface erfüllt, funktioniert er automatisch mit sort.Sort(), sort.Reverse() und sort.IsSorted().
Aufgabe
EinfachLass uns ein sortierbares Produktinventarsystem erstellen, das die Leistungsfähigkeit von Gos sort.Interface demonstriert! Du erstellst einen Product-Typ und implementierst mehrere Sortierstrategien, sodass dieselbe Sammlung auf unterschiedliche Weise sortiert werden kann.
Du organisierst deinen Code über zwei Dateien:
product.go: Definiere deinen Produkttyp und die Sortierimplementierungen.Erstelle eine
Product-Struktur mit drei Feldern:Name(string),Price(float64) undQuantity(int).Erstelle zwei benannte Typen basierend auf
[]Product:ByPrice– zum Sortieren von Produkten nach dem Preis in aufsteigender ReihenfolgeByQuantity– zum Sortieren von Produkten nach der Menge in absteigender Reihenfolge (höchste Menge zuerst)
Jeder Typ muss die drei von
sort.Interfacebenötigten Methoden implementieren:Len(),Less(i, j int)undSwap(i, j int). Die MethodeLessbestimmt die Sortierreihenfolge für den jeweiligen Typ.main.go: Erstelle und sortiere dein Produktinventar.Lies einen Sortiermodus (
priceoderquantity) und anschließend eine Anzahl gefolgt von den Produktdetails ein. Jedes Produkt wird als drei Zeilen angegeben: Name, Preis und Menge.Erstelle ein Slice mit Produkten, sortiere es mithilfe des passenden Sortiertyps abhängig vom Modus und gib anschließend jedes Produkt in diesem Format aus:
[Name]: $[Price] (x[Quantity])Gib Preise mit zwei Dezimalstellen aus.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Sortiermodus (
priceoderquantity) - Zeile 2: Anzahl der Produkte
- Folgende Zeilen: Produktdetails (Name, Preis, Menge – drei Zeilen pro Produkt)
Zum Beispiel bei folgender Eingabe:
price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25Deine Ausgabe sollte folgendermaßen aussehen:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)Und bei folgender Eingabe:
quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25Deine Ausgabe sollte folgendermaßen aussehen:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)Beachte, wie dieselben Produktdaten einfach durch die Verwendung eines anderen benannten Typs unterschiedlich sortiert werden können. Sobald deine Typen sort.Interface erfüllen, funktionieren sie nahtlos mit sort.Sort() aus der Standardbibliothek.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Sortiermodus lesen
var mode string
fmt.Fscanln(reader, &mode)
// Anzahl der Produkte lesen
var count int
fmt.Fscanln(reader, &count)
// Produkte lesen
products := make([]Product, count)
for i := 0; i < count; i++ {
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
priceStr, _ := reader.ReadString('\n')
priceStr = strings.TrimSpace(priceStr)
price, _ := strconv.ParseFloat(priceStr, 64)
qtyStr, _ := reader.ReadString('\n')
qtyStr = strings.TrimSpace(qtyStr)
quantity, _ := strconv.Atoi(qtyStr)
products[i] = Product{Name: name, Price: price, Quantity: quantity}
}
// TODO: Produkte basierend auf dem Modus sortieren
// Wenn mode "price" ist, verwende den ByPrice-Typ
// Wenn mode "quantity" ist, verwende den ByQuantity-Typ
// Verwende sort.Sort() mit dem entsprechenden Typ
// TODO: Gib jedes Produkt im Format aus:
// [Name]: $[Price] (x[Quantity])
// Verwende fmt.Printf mit %.2f für die Preisformatierung
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
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 – Dateiparser11Standardbibliothek & OOP
io.Reader & io.Writersort.Interfacefmt.Stringer-Interfaceencoding/json mit Structshttp.Handler-InterfaceRückblick – REST-API-Modelle3Zeiger & 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