Метод на указателе — и interface не реализован
Классика собеса на Go: дают тип с методом на указателе и просят присвоить значение (не указатель) переменной интерфейсного типа.
type Animal interface { Speak() string }
type Dog struct { Name string }
func (d *Dog) Speak() string { return d.Name + ": woof" }
func main() { var a Animal = Dog{Name: "Rex"} _ = a }
Этот код не компилируется. Ошибка компилятора: Dog does not implement Animal (method Speak has pointer receiver).
Причина в наборе методов (method set). У типа T набор методов — только методы с value receiver. У типа *T — методы и с value, и с pointer receiver. Метод Speak() объявлен на *Dog, значит он входит в method set только *Dog, но не Dog.
Правка простая — передать указатель:
var a Animal = &Dog{Name: "Rex"}
Это компилируется, потому что *Dog реализует интерфейс.
Следом обычно спрашивают: а почему вообще так сделано, почему компилятор не может «просто взять адрес» автоматически? Ответ: Go мог бы разрешить это для адресуемых значений (переменных), но не для временных значений вроде литерала в интерфейсной переменной — у которых нет стабильного адреса в момент присваивания. Правило единое и консистентное: метод с pointer receiver требует именно указатель, без исключений на уровне интерфейсов. Второй частый вопрос: если у структуры есть хотя бы один метод с pointer receiver, стоит ли остальные методы тоже делать на указателе — да, обычно да, чтобы не путать method set и не ловить такие ошибки на других методах того же типа.
Если структура участвует в интерфейсах — выбор receiver не стилистический вопрос, а вопрос совместимости с конкретным интерфейсным типом.
Тренажёр: 1900+ вопросов и задач, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки