Ресиверы (Receivers) - Аналог this и self
В Go нет классов. Вместо этого мы объявляем обычные функции и «привязываем» их к определенному типу (обычно к структуре). Такая привязанная функция называется методом.
Синтаксис метода выглядит так:
func (d Dog) Speak() string {
return "Woof!"
}
Блок (d Dog) перед именем функции называется ресивером (получателем).
Что означает d?
d— это просто имя переменной, через которую ты обращаешься к конкретному экземпляру структуры внутри метода.- Это полный аналог ключевого слова
thisв Java/C++/JS илиselfв Python. - Разработчики Go специально отказались от зарезервированных слов
thisилиself, заставив программиста явно объявлять переменную.
Конвенция именования (Best Practice)
В Go не принято называть ресивер this, self или me.
Общепринятый стандарт — использовать первую букву названия типа (в нижнем регистре) или короткую аббревиатуру:
- Для типа
Dogресивер называютd. - Для типа
User—u. - Для типа
HTTPClient—cилиclient.
Как это используется?
Через переменную d мы получаем доступ к полям именно той собаки, для которой вызвали метод:
type Dog struct {
Name string
Age int
}
// Метод привязан к типу Dog
func (d Dog) Speak() string {
// Обращаемся к полю Name конкретной собаки через ресивер 'd'
return d.Name + " говорит: Woof!"
}
func main() {
myDog := Dog{Name: "Шарик"}
fmt.Println(myDog.Speak()) // Вывод: Шарик говорит: Woof!
}
Value vs Pointer Receiver
Это обязательно спросят: "В чем разница между (d Dog) и (d *Dog)?"
1. Value Receiver (Передача по значению)
func (d Dog) ChangeName() {
d.Name = "Бобик" // Изменит только КОПИЮ
}
- Как работает: Когда ты вызываешь этот метод, Go создает полную копию всей структуры
Dogи передает её в метод. - Следствие: Любые изменения полей внутри метода не повлияют на оригинальную структуру.
- Когда использовать: Если структура маленькая, и метод только читает данные, но не изменяет их.
2. Pointer Receiver (Передача по указателю)
func (d *Dog) ChangeName() {
d.Name = "Бобик" // Изменит ОРИГИНАЛ
}
- Как работает: В метод передается не копия структуры, а указатель (ссылка) на неё в памяти.
- Следствие: Изменения полей внутри метода отразятся на оригинальной структуре.
- Когда использовать:
- Если метод должен изменять состояние структуры.
- Если структура очень большая (много полей), чтобы не тратить память и процессорное время на её копирование при каждом вызове.
Золотое правило: Если хотя бы один метод твоей структуры требует Pointer receiver (
*Dog), то конвенция диктует делать все методы этой структуры с Pointer receiver для единообразия, даже если некоторые из них структуру не меняют.