Historia pytania:
W Go często występują sytuacje, gdy wbudowane typy są niewystarczające i konieczne jest zdefiniowanie własnego typu danych z metodami, aby zrealizować logikę i rozszerzyć funkcjonalność. Osiąga się to poprzez tworzenie typów użytkownika (type) i metod (func (r Receiver) MethodName()).
Problem:
Początkowi programiści często mylą się — jaka jest różnica między deklaracją nowego typu na podstawie istniejącego? Jak prawidłowo zaimplementować metody? Jak rozwiązać problem kopiowania, przesyłania przez wartość/wskaźnik? Mylą się w zakresie widoczności, typu receivera i pracy z wbudowanymi strukturami.
Rozwiązanie:
Aby zdefiniować własny typ, używa się słowa kluczowego type. Metody są zaimplementowane za pomocą receivera (przyjmującego) — to ważne dla pracy z interfejsami.
Przykład kodu:
type MyInt int func (m MyInt) Double() int { return int(m) * 2 } // Dla struktur: type User struct { Name string Age int } func (u *User) Birthday() { u.Age++ } var u = User{"Alice", 30} u.Birthday() // Age = 31
Kluczowe cechy:
Czy typy niestandardowe dziedziczą metody typu bazowego?
Nie. Jeśli zdefiniujesz type MyInt int, to MyInt nie posiada metod int. Na przykład, wywołanie String() lub innych metod typu bazowego nie zadziała.
Czy można definiować metody dla aliasu typu?
Dla aliasu (type MyType = ExistingType) nie można dodać metod. Metody definiuje się tylko dla nowych typów (type MyType ExistingType), a nie dla aliasów.
Jaki receiver używać: wskaźnik czy wartość?
Jeśli metoda ma zmieniać obiekt, lepiej używać wskaźnika. Receiver wartości kopiuje strukturę, co może prowadzić do nieoczekiwanego zachowania, jeśli na przykład struktura zawiera pola, które są wycinkami i mapami.
Przykład kodu:
type Counter struct { value int } func (c *Counter) Inc() { c.value++ } func main() { c := Counter{} c.Inc() // tylko z wskaźnikiem metoda zmieni value }
Programista stworzył type MySlice []int i oczekiwał, że metody []int, takie jak append, będą działać jako metody na typie MySlice. Ostatecznie okazało się, że nie ma żadnych metod, a dostęp do MySlice jako []int bezpośrednio jest niemożliwy.
Zalety:
Wady:
Zdefiniowano type Counter int z metodą Inc, co pozwoliło na użycie go w kilku częściach programu z wspólną logiką i bez powtarzania kodu.
Zalety:
Wady: