Przekazywanie przez wartość a przez referencję
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 21 z 107.
Go jest językiem przekazywania przez wartość. Gdy przekazujesz zmienną do funkcji, Go tworzy kopię tej wartości. Oznacza to, że zmiany wprowadzone wewnątrz funkcji nie wpływają na oryginalną zmienną.
func double(n int) {
n = n * 2
}
func main() {
x := 10
double(x)
fmt.Println(x) // 10 (bez zmian)
}To samo dotyczy struktur. Przekazanie struktury do funkcji kopiuje wszystkie jej pola, więc zmiany wprowadzone wewnątrz funkcji zostają utracone.
type Person struct {
Name string
Age int
}
func birthday(p Person) {
p.Age++
}
func main() {
alice := Person{Name: "Alice", Age: 30}
birthday(alice)
fmt.Println(alice.Age) // 30 (bez zmian)
}Aby zmodyfikować oryginalną wartość, przekaż zamiast tego . Sam wskaźnik jest kopiowany, ale nadal wskazuje ten sam adres pamięci, co pozwala zmienić oryginalne dane.
func birthday(p *Person) {
p.Age++
}
func main() {
alice := Person{Name: "Alice", Age: 30}
birthday(&alice)
fmt.Println(alice.Age) // 31 (zmienione!)
}Używaj wskaźników, gdy chcesz zmodyfikować oryginalną wartość lub przekazać duże struktury, aby uniknąć kosztownego kopiowania. Używaj wartości, gdy chcesz chronić oryginalne dane przed niezamierzonymi zmianami.
Wyzwanie
ŁatwyStwórzmy system koszyka zakupowego, który pokazuje różnicę między przekazywaniem struktur przez wartość a przekazywaniem ich przez wskaźnik. Zobaczysz na własne oczy, że tylko parametry będące wskaźnikami mogą modyfikować oryginalne dane.
Rozmieścisz swój kod w dwóch plikach:
cart.go: Zdefiniuj strukturęCartItemz polamiName(string),Price(float64) iQuantity(int). Utwórz dwie funkcje, które spróbują zaktualizować ilość:UpdateQuantityByValueprzyjmujeCartItem(przez wartość) i nową ilość, a następnie ustawia ilość elementu na nową wartośćUpdateQuantityByPointerprzyjmuje*CartItem(wskaźnik) i nową ilość, a następnie ustawia ilość elementu na nową wartość
TotaldlaCartItem, która zwraca cenę pomnożoną przez ilość.main.go: Odczytaj szczegóły elementu z danych wejściowych, utwórz CartItem, a następnie zademonstruj oba sposoby aktualizacji. Najpierw spróbuj zaktualizować ilość za pomocą funkcji przyjmującej wartość i pokaż wynik, a następnie ponownie zaktualizuj ją za pomocą funkcji przyjmującej wskaźnik i pokaż wynik.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Nazwa elementu
- Wiersz 2: Cena (liczba zmiennoprzecinkowa)
- Wiersz 3: Początkowa ilość (liczba całkowita)
- Wiersz 4: Nowa ilość do ustawienia (liczba całkowita)
Format wyjściowy:
Initial: [Name] x[Quantity] = $[Total]
After value update: [Name] x[Quantity] = $[Total]
After pointer update: [Name] x[Quantity] = $[Total]Na przykład dla danych wejściowych Laptop, 999.99, 1 i 3 wynik powinien wyglądać tak:
Initial: Laptop x1 = $999.99
After value update: Laptop x1 = $999.99
After pointer update: Laptop x3 = $2999.97Zwróć uwagę, że ilość pozostaje równa 1 po aktualizacji przez wartość (funkcja zmodyfikowała kopię), ale zmienia się na 3 po aktualizacji przez wskaźnik (funkcja zmodyfikowała oryginał). Formatuj sumy z dokładnością do dwóch miejsc po przecinku.
Spróbuj swoich sił
package main
import (
"fmt"
)
func main() {
// Wczytaj dane wejściowe
var name string
var price float64
var initialQty, newQty int
fmt.Scanln(&name)
fmt.Scanln(&price)
fmt.Scanln(&initialQty)
fmt.Scanln(&newQty)
// TODO: Utwórz CartItem z wartościami wejściowymi
// TODO: Wypisz stan początkowy, używając formatu:
// fmt.Printf("Initial: %s x%d = $%.2f\n", ...)
// TODO: Spróbuj zaktualizować ilość za pomocą UpdateQuantityByValue
// Następnie wypisz wynik (zauważ, że ilość się nie zmieni)
// TODO: Zaktualizuj ilość za pomocą UpdateQuantityByPointer
// Następnie wypisz wynik (zauważ, że ilość się zmieni)
}
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