Ответ
Ресивер (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), если:
- Тип является небольшим и иммутабельным (например, базовые типы, маленькие структуры, слайсы).
- Вам нужно гарантировать, что метод не изменит исходный объект.
Ответ 18+ 🔞
А, ну так вот, ресивер, блядь! Это ж та самая штука, которая делает из обычной функции — метод, понимаешь? Такая приставка, которая говорит: «Эй, чувак, эта функция принадлежит вот этому типу, и вызывать её надо на нём, как myInstance.MyMethod()». Без этого — просто функция, скукота, а с ним — уже метод, всё по-взрослому.
Их, этих ресиверов, всего два вида, и тут важно не проебаться.
1. Ресивер-указатель (Pointer Receiver) — *T
Это когда ты передаёшь не самого чувака, а его адресок, ссылочку, понимаешь?
- Что делает? Даёт тебе полную власть, сука! Можешь менять оригинал сколько влезет. Всё, что внутри метода накосячишь, останется в исходном объекте навсегда. Как татуировка, блядь.
- Зачем ещё? Экономия, ёпта! Если структура размером с хороший диван, копировать её каждый раз при вызове — это ж овердохуища ресурсов. А тут — чирик, передал адрес, и всё, ты уже внутри.
Смотри, как это выглядит:
type User struct { Name string }
// Метод с ресивером-указателем — тут власть!
func (u *User) SetName(name string) {
u.Name = name // Меняем оригинал, и он меняется навсегда. Всё.
}
2. Ресивер-значение (Value Receiver) — T
А это когда ты работаешь с ксерокопией, блядь. Призраком.
- Что делает? Получает полную, но одноразовую копию объекта. Можешь внутри хоть перекрасить, переименовать — оригинал и ухом не поведёт. Изменения сгорят, как спичка.
- Цена вопроса: Каждый вызов — новое копирование всей структуры. Для маленьких — похуй, а для монстров — пиздец как накладно.
И вот пример:
type User struct { Name string }
// Метод с ресивером-значением — работа с призраком
func (u User) GetName() string {
// u.Name = "new name" // Хуй ты что изменишь, это же копия! Оригинал в безопасности.
return u.Name
}
Так когда что брать-то, ёпта?
*Хватай ресивер-указатель (`T`), если:**
- Тебе надо менять объект. Не просто посмотреть, а именно впендюрить новое значение.
- Структура большая, и копировать её каждый раз — это, блядь, как таскать диван на пятый этаж без лифта. Нахуя?
- Для консистентности, сука! Если хоть один метод у типа уже на указателе, то и остальные делай такими же. Чтобы не было этой хуйни: один метод меняет, а другой нет — волнение ебать, подозрение ебать чувствую!
Бери ресивер-значение (T), если:
- Тип маленький и простой (как int, или маленькая структурка). Скопировать — раз плюнуть.
- Тебе важна гарантия, что метод нихуя не тронет в оригинале. Чистое, непорочное чтение.
- Тип по своей сути иммутабельный (как время, блядь,
time.Time). Его и не должны менять.
Вот и вся философия. Главное — понимать, работаешь ты с оригиналом или с его ксерокопией. А то накосячишь — и потом сидишь, думаешь: «Почему у меня ничего не сохраняется, блядь?». А потому что ресивер не тот выбрал, вот почему!