Ответ
Ресивер (receiver) — это специальный параметр в объявлении метода, который связывает этот метод с определенным типом. Именно благодаря ресиверу мы можем вызывать метод на экземпляре типа, например myInstance.MyMethod()
.
Существует два типа ресиверов:
1. Ресивер-указатель (Pointer Receiver)
Использует указатель на тип (*T
).
- Эффект: Метод может изменять значение, на которое указывает ресивер. Все изменения будут видны в исходном объекте.
- Производительность: Передается только указатель (адрес в памяти), что очень эффективно для больших структур, так как избегается полное копирование объекта.
Пример:
type User struct { Name string }
// Метод с ресивером-указателем
func (u *User) SetName(name string) {
u.Name = name // Изменяет оригинальный объект User
}
2. Ресивер-значение (Value Receiver)
Использует сам тип (T
).
- Эффект: Метод работает с копией значения. Любые изменения внутри метода не затрагивают исходный экземпляр.
- Производительность: Создается полная копия объекта при каждом вызове. Это может быть накладно для больших структур.
Пример:
type User struct { Name string }
// Метод с ресивером-значением
func (u User) GetName() string {
// u.Name = "new name" // Это изменение затронет только копию
return u.Name
}
Когда что использовать?
*Используйте ресивер-указатель (`T`), если:**
- Метод должен изменять состояние объекта.
- Структура большая, и вы хотите избежать накладных расходов на копирование при каждом вызове метода.
- Для соблюдения консистентности: если хотя бы один метод типа имеет ресивер-указатель, остальные методы тоже должны его иметь, чтобы поведение было предсказуемым.
Используйте ресивер-значение (T
), если:
- Тип является небольшим и иммутабельным (например, базовые типы, маленькие структуры, слайсы).
- Вам нужно гарантировать, что метод не изменит исходный объект.