Материал проходит вычитку — возможны неточности.
Урок 41 из 118

Методы и получатели

Миша добавил к 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 неадресуемы
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

type Team struct{ Members []string } с получателем-значением. t := Team{Members: make([]string, 0, 2)}; t.Add("alice"); t.Add("bob"). Что в t.Members?

Вопрос 2 из 3

Тот же Team, но метод RenameFirst пишет t.Members[0] = m по индексу. u := Team{Members: []string{"alice","bob"}}; u.RenameFirst("carol"). Что в u.Members?

Вопрос 3 из 3

Какое правило выбора получателя метода?

Итоги

Методы — функции с получателем; value-receiver — неглубокая копия, pointer-receiver — копия адреса на оригинал; адрес подставляется автоматически, кроме неадресуемых значений.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки