sort.Interface
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 74 z 107.
Pakiet sort stanowi kolejny doskonały przykład projektowania opartego na interfejsach. Aby posortować własną kolekcję, Twój typ musi implementować sort.Interface:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}Te trzy metody dostarczają algorytmowi sortowania wszystkiego, czego potrzebuje: długość kolekcji, sposób porównywania elementów i sposób ich zamiany. Oto jak sprawić, by wycinek własnych struktur można było sortować:
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}]
}Kluczowe jest utworzenie nazwanego typu (ByAge) na podstawie swojej wycinkowej struktury danych. Dzięki temu możesz zdefiniować różne sposoby sortowania tych samych danych. Możesz utworzyć typ ByName z inną implementacją Less, aby sortować alfabetycznie.
Gdy Twój typ spełnia wymagania interfejsu sort.Interface, automatycznie współpracuje z funkcjami sort.Sort(), sort.Reverse() i sort.IsSorted().
Wyzwanie
ŁatwyStwórzmy system magazynowy z produktami, które można sortować, demonstrujący możliwości interfejsu Go sort.Interface! Utworzysz typ Product i zaimplementujesz wiele strategii sortowania, dzięki czemu tę samą kolekcję będzie można sortować na różne sposoby.
Rozmieścisz kod w dwóch plikach:
product.go: Zdefiniuj typ produktu i implementacje sortowania.Utwórz strukturę
Productz trzema polami:Name(string),Price(float64) iQuantity(int).Utwórz dwa nazwane typy bazujące na
[]Product:ByPrice— do sortowania produktów według ceny w porządku rosnącymByQuantity— do sortowania produktów według ilości w porządku malejącym (największa ilość jako pierwsza)
Każdy typ musi implementować trzy metody wymagane przez
sort.Interface:Len(),Less(i, j int)iSwap(i, j int). MetodaLessokreśla kolejność sortowania dla każdego typu.main.go: Utwórz magazyn produktów i posortuj go.Wczytaj tryb sortowania (
pricelubquantity), a następnie liczbę produktów i ich szczegóły. Każdy produkt jest podany w trzech wierszach: nazwa, cena i ilość.Utwórz wycinek produktów, posortuj go za pomocą odpowiedniego typu sortowania w zależności od trybu, a następnie wypisz każdy produkt w następującym formacie:
[Name]: $[Price] (x[Quantity])Wyświetlaj ceny z dwoma miejscami po przecinku.
Dane wejściowe będą następujące:
- Wiersz 1: Tryb sortowania (
pricelubquantity) - Wiersz 2: Liczba produktów
- Kolejne wiersze: Szczegóły produktów (nazwa, cena, ilość — trzy wiersze na produkt)
Na przykład dla danych wejściowych:
price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25Wynik powinien być następujący:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)A dla danych wejściowych:
quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25Wynik powinien być następujący:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)Zwróć uwagę, że te same dane produktów można sortować na różne sposoby, używając po prostu innego nazwanego typu. Gdy Twoje typy spełniają wymagania sort.Interface, bezproblemowo współpracują z sort.Sort() z biblioteki standardowej.
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Wczytaj tryb sortowania
var mode string
fmt.Fscanln(reader, &mode)
// Wczytaj liczbę produktów
var count int
fmt.Fscanln(reader, &count)
// Wczytaj produkty
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: Posortuj produkty według trybu
// Jeśli mode ma wartość "price", użyj typu ByPrice
// Jeśli mode ma wartość "quantity", użyj typu ByQuantity
// Użyj sort.Sort() z odpowiednim typem
// TODO: Wyświetl każdy produkt w formacie:
// [Name]: $[Price] (x[Quantity])
// Użyj fmt.Printf z %.2f do formatowania ceny
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików11Biblioteka standardowa i OOP
io.Reader i io.Writersort.InterfaceInterfejs fmt.Stringerencoding/json ze strukturamiInterfejs http.HandlerPowtórzenie – modele REST API3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online