Какие базовые интерфейсы в Go требуют ресивер по указателю
Что проверяют
Понимаете ли вы правило наборов методов (method sets), а не просто помните «указатель, если меняем поле». Сам интерфейс ничего не требует от ресивера, требование возникает из того, как объявлен метод у типа. Следом обычно дают код, где значение не удовлетворяет интерфейсу, и просят объяснить ошибку компилятора.
Как отвечать
Начните с правила: набор методов типа T включает только методы с ресивером по значению, а набор *T включает оба вида. Если String() объявлен на *T, интерфейсу fmt.Stringer удовлетворяет *T, но не T. При вызове v.M() на адресуемой переменной Go сам возьмёт адрес, а при присваивании значения интерфейсу такой подстановки нет.
Дальше примеры из стандартной библиотеки, где метод по смыслу меняет получателя:
json.Unmarshaler,encoding.TextUnmarshaler:UnmarshalJSONзаполняет структуру, на значении он писал бы в копию;sql.Scanner:Scanзаписывает значение из строки результата в ваш тип;flag.Value:Setсохраняет разобранный аргумент;heap.Interface:PushиPopменяют длину слайса, их объявляют на указателе, аLen,Less,Swapостаются на значении;sync.Locker:Lockуsync.Mutexобъявлен на указателе, копия мьютекса это другой мьютекс, иgo vetругается на такое копирование;io.Writer: уbytes.Bufferвсе методы на указателе, поэтому передают&buf.
Вторая причина: большой структуре указатель экономит копирование. Но это вопрос производительности, а не корректности, и проверяют его бенчмарком.
Где спотыкаются
Объявляют String() или Error() на указателе и удивляются, что fmt.Println(v) печатает поля, а не вашу строку: значение не реализует Stringer, и fmt его не видит.
Говорят, что смешивать ресиверы запрещено. Это рекомендация стиля, компилятор разрешает, просто тип с частью методов на указателе удобнее всегда передавать по указателю.
Путают с адресуемостью: m[key].Inc() при методе на указателе не компилируется, потому что элемент мапы не адресуем. Решение: хранить в мапе *T или вынимать значение, менять и класть обратно.