Ответ
В Go отсутствует явный синтаксис или ключевое слово (такое как implements
в Java/PHP или :
в C#) для указания, что структура реализует интерфейс.
Реализация интерфейса в Go неявная (implicit). Это означает, что если ваша структура (или любой другой тип) имеет все методы, объявленные в интерфейсе, с точно такими же сигнатурами (имена, параметры и возвращаемые значения), то компилятор автоматически считает, что этот тип реализует данный интерфейс.
Пример:
// 1. Определяем интерфейс
type Speaker interface {
Speak() string
}
// 2. Определяем две разные структуры
type Dog struct{}
type Human struct{}
// 3. Реализуем метод Speak() для Dog
func (d Dog) Speak() string {
return "Woof!"
}
// 4. Реализуем метод Speak() для Human
func (h Human) Speak() string {
return "Hello!"
}
// 5. Теперь мы можем использовать Dog и Human там, где ожидается Speaker
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
d := Dog{}
h := Human{}
MakeSound(d) // Работает, т.к. Dog неявно реализует Speaker
MakeSound(h) // Работает, т.к. Human неявно реализует Speaker
}
Зачем это нужно?
Такой подход способствует декаплингу (decoupling) — уменьшению связанности кода. Пакет, определяющий интерфейс, не должен знать о типах, которые его реализуют. И наоборот, пакет с типом не должен импортировать пакеты с интерфейсами, чтобы явно их "наследовать".
Как гарантировать реализацию?
Хотя реализация неявная, часто бывает полезно убедиться на этапе компиляции, что ваш тип действительно реализует нужный интерфейс. Для этого используется идиома с присваиванием нулевого значения переменной-заглушке _
:
// Эта строка вызовет ошибку компиляции, если Dog не реализует Speaker.
// Обычно ее размещают сразу после определения типа.
var _ Speaker = Dog{}