Модульні уроки (2/5)
Методи: значення проти приймача покажчика
Метод у Go — це функція з приймачем: спец
параметр, оголошений між func та назвою методу, який прив’язує
метод до типу. Немає класів: можна визначити методи
будь-який іменований тип, оголошений у поточному пакеті.
Синтаксис
type Person struct {
Name string
}
func (p Person) Greet() string {
return "ciao " + p.Name
}
p := Person{Name: "Ada"}
fmt.Println(p.Greet()) // "ciao Ada"Одержувач p Person робить Greet методом Person. Всередині
p є змінною, як і будь-яка інша.
Приймач значення проти приймача покажчика
// VALUE receiver: operates on a COPY of the value
func (p Person) NameUpper() string {
return strings.ToUpper(p.Name)
}
// POINTER receiver: operates on the original value, can mutate it
func (p *Person) Rename(n string) {
p.Name = n
}За допомогою вказівного приймача ви можете змінювати приймач і вносити зміни видно за межами методу. З приймачем значення ви не можете — ви б змінювати лише локальну копію.
p := Person{Name: "Ada"}
p.Rename("Grace")
fmt.Println(p.Name) // "Grace" — change is visibleКоли використовувати покажчик-приймач
Практичні правила в порядку пріоритету:
- Ви повинні змінити приймач → приймач покажчика. Обов'язковий.
- Структура велика (десятки полів, масиви всередині) → покажчик приймача, щоб уникнути дорогих копій.
- Узгодженість: якщо ХОТАЙ один метод типу має приймач вказівника, використовуйте приймач вказівника для інших теж. Дуже важлива конвенція для інтерфейси (Модуль 6).
- Малі, незмінні, "значення" типи (час. Час, комплексні числа, малі structs) → приймач значення, більш читабельний.
Методи неструктурних типів
Ви можете визначити методи для будь-якого типу NAMED, оголошеного у вашому пакеті:
type Celsius float64
func (c Celsius) ToFahrenheit() float64 {
return float64(c)*9/5 + 32
}
t := Celsius(20)
fmt.Println(t.ToFahrenheit()) // 68Ви не можете визначити їх для типів з інших пакунків (наприклад, int, string): ви повинні
спочатку створіть локальний іменований тип.
Спробуйте
Додайте рядковий метод Greet() (одержувач значення) до Person, який повертає «ciao <Name>».
Показати підказку
Одержувач у дужках ПЕРЕД назвою методу.
Рішення доступне після 3 спроб
Додайте метод Rename(n string) із приймачем POINTER, який змінює p.Name.
Показати підказку
Одержувач покажчика: `(p *Person)`.
Рішення доступне після 3 спроб
Коли слід використовувати приймач вказівника (p *T)?
func (t ?T) M() { ... }Підведення підсумків
- Метод = функція з приймачем:
func (r T) Name(...) ... { ... }. - Одержувач вартості: працює з копією; Приймач вказівника: працює з оригіналом.
- Go автоматично виконує перетворення
T↔*Tна місці виклику. - Приймач покажчика, коли: мутація + велика структура + узгодженість з іншими методами типу.
- Ніколи не змішуйте приймачі значень і покажчиків одного типу.
- Методи йдуть на NAMED типи в поточному пакеті (включаючи non-struct).