🔴 Сложный · 3 очк. Интерфейсы
Скомпилируется ли: type S struct{}; func (s *S) String() string { return "s" }; var _ fmt.Stringer = S{}?
A Да
B Нет, S{} не реализует Stringer
C Да, но вернёт пустую строку
D Зависит от версии Go
Объяснение вопроса

Код не скомпилируется, потому что метод String() определен на pointer receiver (*S), а в переменную передается значение (S{}).

Правило method set

  • Значение типа T имеет методы с value receiver (func (t T))
  • Указатель *T имеет методы и с value, и с pointer receiver
type S struct{}

func (s *S) String() string { return "s" }

// Не скомпилируется: S не реализует fmt.Stringer
var _ fmt.Stringer = S{}

// Скомпилируется: *S реализует fmt.Stringer
var _ fmt.Stringer = &S{}

Почему так устроено

Pointer receiver может модифицировать объект. Если бы Go позволял вызывать pointer-методы на значениях, это создало бы скрытую копию - изменения терялись бы. Поэтому компилятор запрещает это при присвоении интерфейсу.

Когда Go "помогает" автоматически

s := S{}
s.String() // OK! Go автоматически берет &s

// Но при присвоении интерфейсу - нет:
var x fmt.Stringer = s  // ошибка компиляции
var y fmt.Stringer = &s // OK

При прямом вызове метода Go автоматически берет адрес (&s), но при присвоении интерфейсу это невозможно - значение может быть неадресуемым (например, возврат функции).

🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.