Методы и получатели
Миша добавил к FileMeta метод DisplayName и поспорил с Аней о получателе: значение или указатель. Аня согласилась с его выбором, но попросила объяснить его вслух.
метод — функция с получателем; получатель-значение работает с неглубокой копией, получатель-указатель — с копией адреса на оригинал, а компилятор сам подставляет адрес при вызове.
Получатель-значение и получатель-указатель
func (f FileMeta) DisplayName() string {
return f.Name
}
func (f *FileMeta) Rename(name string) {
f.Name = name
}
Получатель пишется между func и именем. Разница между FileMeta и *FileMeta — та же, что между передачей значения и указателя в функцию: получатель-значение получает копию, получатель-указатель — копию адреса, смотрящую на тот же оригинал.
Копия неглубокая: поля-слайсы, карты и указатели внутри структуры остаются общими с оригиналом — полная изоляция наступает, только когда все поля скалярные. И сам указатель-получатель — тоже копия адреса, а не «тот же указатель».
f := FileMeta{Name: "report.pdf"}
f.Rename("report-final.pdf")
fmt.Println(f.Name) // report-final.pdf
Компилятор берёт адрес сам
f.Rename(...) работает, хотя f — значение, а получатель — указатель: компилятор сам передаёт &f. Обратное тоже верно — метод с получателем-значением вызывается на указателе, компилятор разыменует.
Ограничение одно: метод-указатель нельзя вызвать на неадресуемом значении.
FileMeta{Name: "x"}.Rename("y") // ошибка: нельзя взять адрес литерала
Какое правило выбирать
Указатель — если метод меняет состояние или структура большая. Значение — если метод ничего не меняет и структура маленькая. И критерий согласованности: если хотя бы один метод требует указатель, обычно все методы делают на указателе, чтобы не смешивать два стиля в одном типе.
Вы узнаете:
- почему конструкторы по соглашению возвращают
*FileMeta - какие значения в Go неадресуемы
Проверьте себя
type Team struct{ Members []string } с получателем-значением. t := Team{Members: make([]string, 0, 2)}; t.Add("alice"); t.Add("bob"). Что в t.Members?
Тот же Team, но метод RenameFirst пишет t.Members[0] = m по индексу. u := Team{Members: []string{"alice","bob"}}; u.RenameFirst("carol"). Что в u.Members?
Какое правило выбора получателя метода?
правильных ответов
Методы — функции с получателем; value-receiver — неглубокая копия, pointer-receiver — копия адреса на оригинал; адрес подставляется автоматически, кроме неадресуемых значений.
10 000 ₽ · 60 минут · онлайн