Треки
/
Go
Go
/
Салабус
/
Інтерфейси
Ін

Інтерфейси у Go

2 вправи

Про концепцію Інтерфейси

Інтерфейс як набір методів

У найпростішій формі інтерфейсний тип - це набір сигнатур методів. Ось приклад визначення інтерфейсу, яке містить два методи Add і Value:

type Counter interface {
    Add(increment int)
    Value() int
}

Імена параметрів, як-от increment, можна опустити у визначенні інтерфейсу, але часто вони підвищують читабельність.

Назви інтерфейсів у Go не містять слова Interface чи I. Натомість вони часто закінчуються на er, наприклад Reader, Stringer.

Реалізація інтерфейсу

Будь-який тип, що визначає методи інтерфейсу, автоматично, неявно «реалізує» цей інтерфейс. У Go немає ключового слова implements.

Наступний тип реалізує інтерфейс Counter, який ми бачили вище.

type Stats struct {
    value int
    // ...
}

func (s Stats) Add(v int) {
    s.value += v
}

func (s Stats) Value() int {
    return s.value
}

func (s Stats) SomeOtherMethod() {
    // The type can have additional methods not mentioned in the interface.
}

Для реалізації інтерфейсу не має значення, чи має метод отримувача-значення, чи отримувача-вказівника. (Повернімося до концепцій методів, якщо ми не впевнені щодо цього.)

Значення інтерфейсного типу може містити будь-яке значення, яке реалізує ці методи. 1

Це означає, що Stats тепер можна використати будь-де, де потрібен інтерфейс Counter.

func SetUpAnalytics(counter Counter) {
    // ...
}

stats := Stats{}
SetUpAnalytics(stats)
// works because Stats implements Counter

Якби всі параметри функцій і повернені значення мали бути конкретних (тобто не інтерфейсних) типів, це сильно обмежило б можливість їх повторного використання. Використовуючи інтерфейсні типи для параметрів, ми визначаємо лише ту поведінку, яка потрібна функції для виконання своєї роботи. Тепер функцію можна використовувати з параметрами різних конкретних типів, аби лише ці конкретні типи реалізовували інтерфейс. Та сама логіка діє, коли ми використовуємо інтерфейсні типи як повернені значення.

Оскільки інтерфейси реалізуються неявно, тип може легко реалізувати кілька інтерфейсів. Йому достатньо мати всі потрібні методи.

Поєднання інтерфейсів

Визначення інтерфейсу може містити інші інтерфейси. Ось приклад зі стандартної бібліотеки.

type ReadCloser interface {
	Reader
	Closer
}

// Based on these interfaces:

type Reader interface {
	Read(p []byte) (n int, err error)
}

type Closer interface {
	Close() error
}

Щоб визначити ReadCloser, визначення інтерфейсу не повторює сигнатури методів Read і Close, а використовує наявні визначення Reader і Closer.

Порожній інтерфейс

У Go є один дуже особливий інтерфейсний тип - порожній інтерфейс, який не містить жодного методу. Порожній інтерфейс записують так: interface{}. У Go 1.18 або новішій версії можна також використовувати any. Його визначили як псевдонім.

Оскільки порожній інтерфейс не має методів, кожен тип реалізує його неявно. Це корисно, коли ми визначаємо функцію, яка може загально приймати будь-яке значення. У такому разі параметр функції має тип порожнього інтерфейсу.

Наприклад:

func AnythingGoes(i interface{}) string {
    if i == 0 {
        return "zero"
    }
    if i == "" {
        return "empty string"
    }
    return "something else"
}
  1. Tour of Go: Interfaces ↩

Редагувати через GitHub Посилання відкривається в новому вікні або вкладці

Вивчити концепцію Інтерфейси

Практика заблокована

Розблокуйте ще 1 вправу, щоб практикувати концепцію Інтерфейси