Wskaźniki do struktur
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 20 z 107.
Podczas pracy ze strukturami często używa się wskaźników, aby uniknąć kopiowania dużych struktur danych i modyfikować oryginalną strukturę. Wskaźnik do struktury przechowuje adres pamięci tej instancji struktury.
Możesz utworzyć wskaźnik do struktury za pomocą operatora & dla istniejącej struktury lub używając operatora adresu bezpośrednio z literałem struktury.
type Person struct {
Name string
Age int
}
p := Person{Name: "Alice", Age: 30}
ptr := &p // wskaźnik do istniejącej struktury
// Lub utwórz bezpośrednio
ptr2 := &Person{Name: "Bob", Age: 25}Go zapewnia wygodny skrót podczas uzyskiwania dostępu do pól struktury za pośrednictwem wskaźnika. Zamiast pisać (*ptr).Name, możesz po prostu napisać ptr.Name. Go automatycznie dereferencjonuje wskaźnik za Ciebie.
ptr := &Person{Name: "Alice", Age: 30}
// Oba działają identycznie
fmt.Println((*ptr).Name) // jawna dereferencja
fmt.Println(ptr.Name) // automatyczna dereferencjaTo automatyczne wyłuskiwanie wskaźnika dotyczy również modyfikowania pól. Zmiany wprowadzane za pośrednictwem wskaźnika wpływają na oryginalną strukturę.
p := Person{Name: "Alice", Age: 30}
ptr := &p
ptr.Age = 31 // modyfikuje oryginał
fmt.Println(p.Age) // 31Wskaźniki do struktur są niezbędne we wzorcach programowania obiektowego w Go. Umożliwiają metodom modyfikowanie stanu odbiorcy, pozwalają efektywnie przekazywać duże struktury do funkcji i stanowią podstawę tworzenia połączonych struktur danych, takich jak drzewa i listy.
Wyzwanie
ŁatwyStwórzmy system konta bankowego, który pokazuje, jak wskaźniki do struktur pozwalają efektywnie modyfikować oryginalne dane. Utworzysz konto, które można aktualizować za pomocą operacji na wskaźnikach.
Rozmieścisz kod w dwóch plikach:
account.go: Zdefiniuj strukturęBankAccountz polamiOwner(string),Balance(float64) iAccountNumber(string). Utwórz funkcję o nazwieNewAccount, która przyjmuje nazwę właściciela i numer konta jako parametry oraz zwraca wskaźnik do nowej strukturyBankAccountz saldem początkowym równym 0. Utwórz również funkcjęDeposit, która przyjmuje wskaźnik*BankAccounti kwotę, a następnie dodaje tę kwotę do salda konta za pośrednictwem wskaźnika.main.go: Odczytaj informacje o koncie z wejścia, utwórz konto za pomocą funkcji konstruktora (która zwraca wskaźnik), dokonaj wpłaty za pomocą wskaźnika i wyświetl szczegóły konta, aby potwierdzić, że saldo zostało zmodyfikowane.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Imię i nazwisko właściciela
- Wiersz 2: Numer konta
- Wiersz 3: Kwota wpłaty (float)
Format wyjściowy:
Account: [AccountNumber]
Owner: [Owner]
Balance: [Balance]Na przykład dla danych John Smith, ACC-12345 i 500.50 wynik powinien wyglądać następująco:
Account: ACC-12345
Owner: John Smith
Balance: 500.50Pamiętaj, że funkcja NewAccount powinna zwracać *BankAccount za pomocą operatora &, a funkcja Deposit może bezpośrednio modyfikować saldo za pośrednictwem wskaźnika, korzystając z automatycznego dereferencjonowania w Go (np. account.Balance zamiast (*account).Balance).
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 konta
accountNumber, _ := reader.ReadString('\n')
accountNumber = strings.TrimSpace(accountNumber)
// Odczytaj kwotę wpłaty
amountStr, _ := reader.ReadString('\n')
amountStr = strings.TrimSpace(amountStr)
amount, _ := strconv.ParseFloat(amountStr, 64)
// TODO: Utwórz nowe konto za pomocą funkcji NewAccount (zwraca wskaźnik)
// TODO: Dokonaj wpłaty za pomocą funkcji Deposit, przekazując wskaźnik do konta
// TODO: Wypisz dane konta w wymaganym formacie:
// Konto: [AccountNumber]
// Właściciel: [Owner]
// Saldo: [Balance]
}
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