Вопрос с собеседования · Go

Когда метод должен иметь получатель-указатель, а когда — значение?

JuniorМетоды и интерфейсы
Ещё спрашивают так:
  • Почему структура не удовлетворяет интерфейсу, хотя метод есть?
Коротко

Указатель func (s *Svc) — если метод меняет получателя, структура большая или содержит то, что нельзя копировать (sync.Mutex). Значение func (p Point) — для маленьких неизменяемых типов. Получатели одного типа делают единообразными.

  • Методы с получателем-указателем входят в набор методов только *T, а не T
  • Поэтому T не удовлетворяет интерфейсу, если нужный метод объявлен на *T
  • Вызов p.Method() на адресуемой переменной Go сам возьмёт адрес

А ещё Копирование структуры с мьютексом — go vet предупредит (copylocks)

Подробно

Получатель-значение получает копию: изменения внутри метода не видны снаружи. Для Point{X, Y} это естественно и безопасно.

Получатель-указатель работает с оригиналом. Нужен, когда метод меняет состояние, когда структура большая (копирование при каждом вызове), когда в ней мьютекс или другие поля, которые нельзя копировать.

Наборы методов. У типа T — методы с получателем T; у *T — и T, и *T. Значение в интерфейсе неадресуемо, поэтому Go не может взять его адрес, чтобы вызвать метод указателя, — отсюда ошибка компиляции «does not implement (method has pointer receiver)».

Правило единообразия: если хотя бы один метод требует указателя, все методы типа обычно объявляют на указателе.

Пример

type Counter struct{ n int }
func (c *Counter) Inc()      { c.n++ }      // меняет — указатель
func (c Counter) Value() int { return c.n }

type Incer interface{ Inc() }
var _ Incer = &Counter{}    // ок
var _ Incer = Counter{}     // ошибка: Inc объявлен на *Counter

Что хотят услышать

  • Критерии выбора.
  • Наборы методов и интерфейсы.

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

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗Получатель-значение позволяет методу менять исходную структуру
  • ✓Указатель — если метод меняет получателя или тип нельзя копировать
  • ✗Тип T всегда удовлетворяет интерфейсу с методами получателя *T, Go возьмёт адрес сам
  • ✗Получатели одного типа лучше делать вперемешку

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования