У найпростішому вигляді інтерфейсний тип - це набір сигнатур методів.
Ось приклад визначення інтерфейсу, який містить два методи 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
Оскільки інтерфейси реалізуються неявно, тип може легко реалізувати кілька інтерфейсів. Для цього йому достатньо мати всі потрібні методи.
У Go є один дуже особливий інтерфейсний тип: порожній інтерфейс, який не містить жодного методу.
Порожній інтерфейс записують так: interface{}.
any - це псевдонім для interface{}, і його використовують частіше.
Оскільки порожній інтерфейс не має методів, кожен тип реалізує його неявно. Це допомагає визначати функції, які можуть узагальнено приймати будь-яке значення. У такому разі параметр функції має порожній інтерфейсний тип.
Новий аеропорт у Берліні найняв розробників для своєї лабораторії роботів, і ми починаємо там працювати. У них є незграбні, трохи схожі на людей роботи, яких вони намагаються використати, щоб покращити обслуговування клієнтів.
Наше перше завдання на цій роботі - написати програму, щоб робот міг вітати людей їхньою рідною мовою після того, як вони відсканували свої паспорти на стійці самообслуговування.
Робот пишається своїми здібностями, тож він завжди спершу скаже, якою мовою вміє говорити, а потім привітає людину. Наприклад, якщо хтось сканує німецький паспорт, робот скаже:
I can speak German: Hallo Dietrich!
Ми не будемо писати код для різних мов самостійно, тож треба структурувати код робота так, щоб інші розробники могли легко додавати нові мови згодом.
Як перший крок визначмо інтерфейс Greeter із двома методами.
LanguageName, який повертає назву мови (string), якою робот має вітати відвідувача.Greet, який приймає імʼя відвідувача (string) і повертає string із привітанням конкретною мовою.Далі реалізуймо функцію SayHello, яка приймає імʼя відвідувача та будь-що, що реалізує інтерфейс Greeter, як аргументи й повертає потрібний рядок із привітанням.
Наприклад, уявімо німецьку реалізацію Greeter, у якій LanguageName повертає "German", а Greet повертає "Hallo {name}!":
SayHello("Dietrich", germanGreeter)
// => "I can speak German: Hallo Dietrich!"
Тепер наше завдання - зробити так, щоб робот працював для людей, які сканують італійські паспорти.
Для цього створімо структуру Italian і реалізуймо два методи, потрібні, щоб структура задовольняла інтерфейс Greeter, який ми створили в завданні 1.
Італійською можна привітатися так: "Ciao {name}!".
Перш ніж закінчити на сьогодні, треба також допрацювати функціональність, щоб вітати людей португальською.
Для цього створімо структуру Portuguese і тут так само реалізуймо два методи, потрібні, щоб структура задовольняла інтерфейс Greeter.
Португальською можна привітатися так: "Olá {name}!".
Зареєструйтеся на Exercism, щоб вивчати й опановувати Go, а також 34 концепції166 вправ та справжнє наставництво від людей, і все це безкоштовно.