Podstawy wskaźników w Go
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 19 z 107.
Wskaźnik to zmienna, która przechowuje adres pamięci innej zmiennej. Zamiast przechowywać bezpośrednio wartość, przechowuje lokalizację, w której ta wartość znajduje się w pamięci. Wskaźniki są podstawowym elementem Go i są niezbędne do wydajnego przetwarzania danych.
Aby utworzyć wskaźnik, użyj operatora &, aby uzyskać adres zmiennej, oraz operatora *, aby zadeklarować typ wskaźnikowy lub uzyskać dostęp do wartości znajdującej się pod tym adresem.
x := 42
p := &x // p przechowuje adres pamięci x
fmt.Println(p) // 0xc000018030 (adres pamięci)
fmt.Println(*p) // 42 (wartość pod tym adresem)Operator & oznacza „adres” i zwraca wskaźnik. Operator *, gdy jest używany na wskaźniku, oznacza „wartość pod adresem” i jest nazywany dereferencją. Możesz także modyfikować oryginalną wartość za pomocą wskaźnika.
x := 10
p := &x
*p = 25 // zmień wartość przez wskaźnik
fmt.Println(x) // 25 (zmieniono oryginalną zmienną)Typ wskaźnika zapisuje się jako *T, gdzie T jest typem, na który wskazuje wskaźnik. Wskaźnik do wartości typu int ma typ *int.
var p *int // deklaruje wskaźnik na int
x := 100
p = &x // p wskazuje teraz na xWartością zerową wskaźnika jest nil, co oznacza, że nie wskazuje on na nic. Próba dereferencji wskaźnika nil powoduje panikę w czasie wykonywania, dlatego zawsze upewnij się, że wskaźniki są zainicjalizowane przed użyciem.
Wyzwanie
ŁatwyZbudujmy prosty program zamieniający wartości, który pokazuje, jak wskaźniki pozwalają modyfikować zmienne za pomocą ich adresów w pamięci.
Rozmieścisz kod w dwóch plikach:
swap.go: Utwórz funkcję o nazwieSwapValues, która przyjmuje jako parametry dwa wskaźniki*int. Ta funkcja powinna zamienić wartości, na które wskazują te wskaźniki. Po jej wywołaniu każda zmienna powinna przechowywać pierwotną wartość drugiej zmiennej. Funkcja niczego nie zwraca; modyfikuje wartości bezpośrednio za pomocą wskaźników.main.go: Wczytaj z wejścia dwie liczby całkowite i zapisz je w zmiennych, a następnie użyj funkcjiSwapValues, aby zamienić ich wartości. Wypisz obie wartości przed zamianą i po niej, aby pokazać zmianę.
Dane wejściowe będą następujące:
- Wiersz 1: Pierwsza liczba całkowita
- Wiersz 2: Druga liczba całkowita
Format wyjściowy:
Before: a=[first] b=[second]
After: a=[first] b=[second]Na przykład dla danych 10 i 25 wynik powinien wyglądać następująco:
Before: a=10 b=25
After: a=25 b=10Pamiętaj, aby użyć operatora &, przekazując zmienne do funkcji, oraz operatora * wewnątrz funkcji, aby uzyskać dostęp do rzeczywistych wartości i je modyfikować.
Spróbuj swoich sił
package main
import "fmt"
func main() {
// Wczytaj dwie liczby całkowite z wejścia
var a, b int
fmt.Scanln(&a)
fmt.Scanln(&b)
// Wypisz wartości przed zamianą
fmt.Printf("Before: a=%d b=%d\n", a, b)
// TODO: Wywołaj funkcję SwapValues ze wskaźnikami do a i b
// Pamiętaj, aby użyć operatora & do przekazania adresów
// Wypisz wartości po zamianie
fmt.Printf("After: a=%d b=%d\n", a, b)
}
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