Podstawy osadzania struktur
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 35 z 107.
Osadzanie struktur to mechanizm języka Go umożliwiający umieszczenie jednego typu struktury wewnątrz innej. Zamiast używać nazwy pola, po prostu podajesz typ, a Go udostępnia pola osadzonej struktury w strukturze zewnętrznej.
Oto podstawowa składnia:
type Address struct {
City string
Country string
}
type Person struct {
Name string
Address // osadzone - bez nazwy pola
}
Gdy osadzisz Address w Person, możesz uzyskać bezpośredni dostęp do osadzonych pól w zewnętrznej strukturze:
func main() {
p := Person{
Name: "Alice",
Address: Address{
City: "London",
Country: "UK",
},
}
fmt.Println(p.City) // London - dostęp bezpośredni
fmt.Println(p.Country) // UK - dostęp bezpośredni
fmt.Println(p.Address.City) // również działa
}
Zwróć uwagę, że p.City działa bez konieczności jawnego zapisywania p.Address.City. Go automatycznie udostępnia pola osadzonej struktury tak, jakby należały do zewnętrznej struktury. W razie potrzeby nadal możesz uzyskać do nich dostęp za pomocą nazwy osadzonego typu.
To różni się od zwykłych zagnieżdżonych struktur, w których zawsze musisz używać nazwy pola, aby uzyskać dostęp do pól wewnętrznych. Osadzanie tworzy bardziej płaskie i wygodniejsze API, jednocześnie zachowując logiczne grupowanie powiązanych danych.
Wyzwanie
ŁatwyStwórzmy system rejestracji pojazdów, który wykorzystuje osadzanie struktur, aby utworzyć przejrzysty i uporządkowany model danych. Oddzielisz informacje kontaktowe od danych pojazdu, zachowując jednocześnie bezpośredni dostęp do wszystkich pól dzięki osadzaniu.
Rozmieścisz kod w dwóch plikach:
vehicle.go: Utwórz dwie struktury, które współpracują dzięki osadzaniu:- Strukturę
ContactInfoz polamiOwnerNameiPhone(oba typu string) - Strukturę
Vehicle, która osadzaContactInfo(bez nazwy pola) i dodaje własne polaMake,ModeliYear
SummarydlaVehicle, która zwraca sformatowany ciąg zawierający wszystkie informacje o pojeździe i dane kontaktowe.- Strukturę
main.go: Odczytaj z wejścia dane pojazdu i właściciela, utwórz instancjęVehiclez osadzonymContactInfoi pokaż, jak uzyskać dostęp do osadzonych pól zarówno bezpośrednio, jak i przez nazwę osadzonego typu. Na końcu wypisz podsumowanie pojazdu.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Imię i nazwisko właściciela
- Wiersz 2: Numer telefonu
- Wiersz 3: Marka pojazdu
- Wiersz 4: Model pojazdu
- Wiersz 5: Rok (liczba całkowita)
Metoda Summary powinna zwracać ciąg w następującym formacie:
[Year] [Make] [Model] - Owner: [OwnerName], Phone: [Phone]W pliku głównym pokaż promocję pól, wypisując:
- Imię i nazwisko właściciela uzyskane bezpośrednio z Vehicle (np.
v.OwnerName) - Numer telefonu uzyskany przez osadzony typ (np.
v.ContactInfo.Phone) - Pełne podsumowanie z metody
Summary
Na przykład dla danych Alice Smith, 555-1234, Toyota, Camry i 2023 wynik powinien wyglądać następująco:
Alice Smith
555-1234
2023 Toyota Camry - Owner: Alice Smith, Phone: 555-1234Zwróć uwagę, że oba sposoby dostępu działają: bezpośredni dostęp dzięki promocji pól oraz jawny dostęp przez nazwę osadzonego typu. Daje ci to elastyczność w pracy z osadzonymi danymi.
Spróbuj swoich sił
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Odczytaj imię i nazwisko właściciela
ownerName, _ := reader.ReadString('\n')
ownerName = strings.TrimSpace(ownerName)
// Odczytaj numer telefonu
phone, _ := reader.ReadString('\n')
phone = strings.TrimSpace(phone)
// Odczytaj markę pojazdu
make, _ := reader.ReadString('\n')
make = strings.TrimSpace(make)
// Odczytaj model pojazdu
model, _ := reader.ReadString('\n')
model = strings.TrimSpace(model)
// Odczytaj rok
yearStr, _ := reader.ReadString('\n')
yearStr = strings.TrimSpace(yearStr)
year, _ := strconv.Atoi(yearStr)
// TODO: Utwórz instancję Vehicle z osadzonym ContactInfo
// Użyj wartości odczytanych powyżej z wejścia
// TODO: Wypisz imię i nazwisko właściciela, uzyskując do nich dostęp bezpośrednio przez Vehicle (promowanie pól)
// Przykład: fmt.Println(v.OwnerName)
// TODO: Wypisz numer telefonu, uzyskując do niego dostęp przez nazwę osadzonego typu
// Przykład: fmt.Println(v.ContactInfo.Phone)
// TODO: Wypisz pełne podsumowanie za pomocą metody Summary
// Przykład: fmt.Println(v.Summary())
// Usuń te linie po zaimplementowaniu rozwiązania
_ = ownerName
_ = phone
_ = make
_ = model
_ = year
}
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ów3Wskaź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