пятница, 30 октября 2020 г.

Go style guides: указатели на интерфейсы, проверка интерфейса

Указатели на интерфейсы

Вам почти никогда не понадобится указатель на интерфейс. Вы должны передавать интерфейсы как значения - базовые данные по-прежнему могут быть указателем.

Интерфейс состоит из двух полей:

  • Указатель на некоторую информацию, зависящую от типа. Вы можете думать об этом как о "типе".
  • Указатель данных. Если сохраненные данные представляют собой указатель, они сохраняются напрямую. Если сохраненные данные представляют собой значение, то сохраняется указатель на значение.

Если вы хотите, чтобы методы интерфейса изменяли базовые данные, вы должны использовать указатель.

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

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

  • Экспортируемые типы, которые необходимы для реализации определенных интерфейсов как часть их контракта API.
  • Экспортированные или неэкспортированные типы, которые являются частью коллекции типов, реализующих один и тот же интерфейс
  • Другие случаи, когда нарушение интерфейса нарушит работу пользователей

Плохой пример:

type Handler struct {
  // ...
}

func (h *Handler) ServeHTTP(
  w http.ResponseWriter,
  r *http.Request,
) {
  ...
}

Хороший пример:

type Handler struct {
  // ...
}

var _ http.Handler = (*Handler)(nil)

func (h *Handler) ServeHTTP(
  w http.ResponseWriter,
  r *http.Request,
) {
  // ...
}

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

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

type LogHandler struct {
  h   http.Handler
  log *zap.Logger
}

var _ http.Handler = LogHandler{}

func (h LogHandler) ServeHTTP(
  w http.ResponseWriter,
  r *http.Request,
) {
  // ...
}


Читайте также:


Комментариев нет:

Отправить комментарий