Проверка рациональности интерфейса

Проверка соответствия интерфейса на этапе компиляции. Это включает в себя:

  • Проверку экспортируемого типа, который реализует конкретный интерфейс в рамках API интерфейса
  • Типы (как экспортируемые, так и неэкспортируемые), реализующие тот же интерфейс, принадлежат к коллекции реализующих типов
  • Любые сценарии, нарушающие проверку рациональности интерфейса, приведут к остановке компиляции и уведомлению пользователя

Дополнение: Вышеперечисленные три пункта - это механизмы проверки интерфейса компилятора. Общая идея заключается в том, что ошибки при использовании интерфейса будут сообщаться на этапе компиляции. Поэтому этот механизм может быть использован для выявления некоторых проблем на этапе компиляции.

Не рекомендуемый подход:

// Если Handler не реализует http.Handler, произойдет ошибка во время выполнения
type Handler struct {
  // ...
}
func (h *Handler) ServeHTTP(
  w http.ResponseWriter,
  r *http.Request,
) {
  ...
}

Рекомендуемый подход:

type Handler struct {
  // ...
}
// Используется для запуска механизма проверки интерфейса на рациональность на этапе компиляции
// Если Handler не реализует http.Handler, произойдет ошибка на этапе компиляции
var _ http.Handler = (*Handler)(nil)
func (h *Handler) ServeHTTP(
  w http.ResponseWriter,
  r *http.Request,
) {
  // ...
}

Если *Handler не соответствует интерфейсу http.Handler, оператор var _ http.Handler = (*Handler)(nil) не будет компилироваться.

Справа от присваивания должно быть нулевое значение утвержденного типа. Для типов указателей (например, *Handler), срезов и карт это nil; для типов структур это пустая структура.

type LogHandler struct {
  h   http.Handler
  log *zap.Logger
}
var _ http.Handler = LogHandler{}
func (h LogHandler) ServeHTTP(
  w http.ResponseWriter,
  r *http.Request,
) {
  // ...
}