Материал проходит вычитку — возможны неточности.
Урок 42 из 118

Интерфейс — контракт

У «Полки» появился второй способ хранения файлов — облачный S3. Сергей предложил общий договор Storage, и Миша написал две реализации: локальный диск и облако. Тесты переехали на заглушку.

Главная мысль

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

Контракт

type Storage interface {
    Save(name string, data []byte) error
}

type LocalDisk struct{}
func (LocalDisk) Save(name string, data []byte) error {
    // пишет файл на локальный диск
    return nil
}

type S3Backend struct{}
func (S3Backend) Save(name string, data []byte) error {
    // кладёт объект в облако
    return nil
}

var st Storage = LocalDisk{}

Интерфейс — это контракт: «у меня есть метод Save с такой сигнатурой». Кто его выполняет — локальный диск или облако — неважно. Это про поведение, а не про данные: интерфейс не может содержать поля.

Неявная реализация

В Go нет слова implements. Тип удовлетворяет интерфейсу автоматически, если его method set покрывает все методы интерфейса:

Go

Это ключевое отличие от языков с явной реализацией: интерфейс можно ввести задним числом, и существующие типы «подойдут» под него без правок. Стандартная библиотека так и устроена: io.Reader, io.Writer, fmt.Stringer — маленькие интерфейсы, которым удовлетворяют тысячи типов по всему коду. Так же получилось в «Полке»: LocalDisk написан давно и ничего не знал про Storage, но подошёл под него без единой правки.

Интерфейс принимает реализацию

Функция, принимающая интерфейс, работает с любым типом, выполняющим контракт:

func persist(st Storage, name string, data []byte) error {
    return st.Save(name, data)
}

persist(LocalDisk{}, "report.pdf", data)
persist(S3Backend{}, "report.pdf", data)
В следующем уроке

Вы узнаете:

  • что даёт пустой интерфейс any
  • как интерфейс помогает делать моки в тестах
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

Как тип удовлетворяет интерфейсу в Go?

Вопрос 2 из 3

Что может содержать интерфейс?

Вопрос 3 из 3

Можно ли ввести интерфейс задним числом для уже написанного типа?

Итоги

Интерфейс — контракт о методах. Реализация неявная: тип подходит, если сигнатуры сошлись. Интерфейс принимает любую реализацию — отсюда гибкость и тестируемость кода.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки