0Pricing
Go Academy · Lekcja

Odbiorniki wskaźnikowe metod

Modyfikowanie stanu struktury za pomocą odbiorników wskaźnikowych

Odbiorniki wskaźnikowe metod to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.

Podsumowanie: odbiorca wartości a odbiorca wskaźnika

Odbiorca wartości działa na kopii struktury. Odbiorca wskaźnika działa na oryginale. Używaj odbiorców wskaźnikowych zawsze, gdy metoda musi modyfikować stan.

Modyfikowanie za pomocą odbiorcy wskaźnikowego

Tylko odbiorca wskaźnikowy może modyfikować strukturę:

package main
import "fmt"

type Stack struct{ items []int }

func (s *Stack) Push(v int) { s.items = append(s.items, v) }
func (s *Stack) Pop() int {
    n := len(s.items) - 1
    v := s.items[n]
    s.items = s.items[:n]
    return v
}

func main() {
    var st Stack
    st.Push(1); st.Push(2)
    fmt.Println(st.Pop()) // 2
}

Zasada spójności

Jeśli którakolwiek metoda danego typu wymaga odbiorcy wskaźnikowego, wszystkie metody powinny używać odbiorców wskaźnikowych. Mieszanie obu rodzajów powoduje problemy ze spełnianiem interfejsów:

package main
import "fmt"

type Counter struct{ n int }

func (c *Counter) Inc()   { c.n++ }   // pointer
func (c *Counter) Val() int { return c.n } // pointer too

func main() {
    c := &Counter{}
    c.Inc(); c.Inc()
    fmt.Println(c.Val()) // 2
}

Spełnianie interfejsu

Metoda z odbiorcą wskaźnikowym znajduje się tylko w zbiorze metod typu *T, a nie typu T. Wpływa to na spełnianie interfejsów:

package main
import "fmt"

type Writer interface{ Write([]byte) }

type File struct{ name string }
func (f *File) Write(b []byte) { fmt.Println(string(b)) }

func main() {
    var w Writer = &File{"out.txt"} // OK
    // var w Writer = File{} — compile error
    w.Write([]byte("hello"))
}

Automatyczne pobieranie adresu

Go automatycznie pobiera adres podczas wywoływania metody z odbiorcą wskaźnikowym na wartości, której można pobrać adres:

package main
import "fmt"

type Box struct{ V int }
func (b *Box) Double() { b.V *= 2 }

func main() {
    b := Box{5}
    b.Double()          // Go does (&b).Double()
    fmt.Println(b.V)    // 10
}

Wartości bez adresu

Nie można wywoływać metod z odbiorcą wskaźnikowym na wartościach, których nie można adresować (elementach mapy, wartościach zwracanych przez funkcje, które nie zostały przypisane do zmiennych):

package main

type T struct{ V int }
func (t *T) Set(v int) { t.V = v }

func getT() T { return T{} }

func main() {
    var t T
    t.Set(1)       // OK — t is addressable
    // getT().Set(1) — ERROR: cannot take address of getT()
    _ = t
}

Odbiorcy dużych struktur

W przypadku dużych struktur zawsze używaj odbiorców wskaźnikowych, aby uniknąć kosztownego kopiowania przy każdym wywołaniu metody:

package main

type Image struct{ pixels [1024][1024]uint8 }

// Value receiver copies 1MB per call!
func (img Image) Bad() uint8 { return img.pixels[0][0] }

// Pointer receiver — zero copy
func (img *Image) Good() uint8 { return img.pixels[0][0] }

func main() { _ = Image{} }

Odbiorcy wskaźnikowi nil

Metody z odbiorcami wskaźnikowymi mogą poprawnie obsługiwać wartość nil:

package main
import "fmt"

type List struct{ head *node }
type node struct{ val int; next *node }

func (l *List) Len() int {
    if l == nil { return 0 }
    count := 0
    for n := l.head; n != nil; n = n.next { count++ }
    return count
}

func main() {
    var l *List
    fmt.Println(l.Len()) // 0
}

Osadzanie a odbiorcy wskaźnikowi

Gdy osadzasz typ z odbiorcami wskaźnikowymi, zewnętrzna struktura również musi być używana jako wskaźnik, aby uzyskać promowane metody:

package main
import "fmt"

type Base struct{ V int }
func (b *Base) Set(v int) { b.V = v }

type Derived struct{ Base }

func main() {
    d := &Derived{}
    d.Set(42)           // promoted pointer-receiver method
    fmt.Println(d.V)    // 42
}

Kopiowanie muteksów

Nigdy nie kopiuj struktury zawierającej sync.Mutex — zawsze używaj odbiorcy wskaźnikowego albo przekazuj ją przez wskaźnik. Skopiowanie zablokowanego muteksu prowadzi do zakleszczenia:

package main
import "sync"

type Safe struct {
    mu sync.Mutex
    v  int
}

// Correct: pointer receiver
func (s *Safe) Set(v int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.v = v
}

func main() { _ = Safe{} }

go vet wykrywa błędy

Uruchom go vet ./..., aby wykryć typowe błędy związane z odbiorcami wskaźnikowymi, takie jak kopiowanie muteksów i blokad. Jest to część potoków go build oraz kontroli CI.

Szybkie sprawdzenie

W zbiorze metod jakich typów znajduje się metoda z odbiorcą wskaźnikowym?

Podsumowanie

Najważniejsze informacje:

  • Odbiorcy wskaźnikowi modyfikują wartości, a odbiorcy wartości — nie
  • Wszystkie metody danego typu powinny używać tego samego rodzaju odbiorcy
  • Tylko *T spełnia interfejsy wymagające metod z odbiorcami wskaźnikowymi
  • Nigdy nie kopiuj struktur zawierających muteksy — używaj odbiorców wskaźnikowych

Polecenie ćwiczeniowe

Zaimplementuj strukturę Queue z metodami Enqueue(int), Dequeue() (int, bool) i Len() int korzystającymi z odbiorców wskaźnikowych i opartymi na wycinku []int.

Często zadawane pytania

Czy lekcja „Odbiorniki wskaźnikowe metod” jest bezpłatna?

Tak — pełny tekst „Odbiorniki wskaźnikowe metod” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Odbiorniki wskaźnikowe metod”?

Modyfikowanie stanu struktury za pomocą odbiorników wskaźnikowych Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Go Academy?

Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Odbiorniki wskaźnikowe metod”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?

Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Czym są wskaźniki?
  2. Wskaźniki i funkcje
  3. Odbiorniki wskaźnikowe metod
  4. new() i kiedy używać wskaźników
← Powrót do Go Academy