Ответ
Основное отличие интерфейсов в Go заключается в их неявной реализации, что также называют "утиной типизацией" (duck typing). В классических ООП-языках, таких как Java или C#, реализация интерфейса всегда явная.
// Определяем интерфейс
type Writer interface {
Write(p []byte) (n int, err error)
}
// Определяем тип. Он не имеет никакой информации об интерфейсе Writer.
type ConsoleWriter struct{}
// Реализуем метод с той же сигнатурой, что и в интерфейсе.
func (cw ConsoleWriter) Write(p []byte) (int, error) {
return fmt.Println(string(p))
}
// Переменной типа Writer можно присвоить значение типа ConsoleWriter,
// так как ConsoleWriter *неявно* удовлетворяет интерфейсу.
var w Writer = ConsoleWriter{}
Ключевые отличия:
-
Неявная реализация (Утиная типизация): Тип удовлетворяет интерфейсу автоматически, если у него есть все методы этого интерфейса. Не нужно ключевое слово
implements
.- Следствие: Это позволяет реализовывать интерфейсы для типов из сторонних библиотек, не изменяя их исходный код.
-
Отсутствие иерархии: В Go интерфейсы не создают иерархии наследования. Они определяют поведение (что тип умеет делать), а не родство (чем тип является).
-
Композиция интерфейсов: Интерфейсы в Go легко встраиваются друг в друга, создавая более сложные контракты из простых.
type ReadWriter interface { Reader Writer }
-
Пустой интерфейс (
any
): Типinterface{}
(с версии Go 1.18 — псевдонимany
) может хранить значение абсолютно любого типа. Это мощный инструмент для создания гибких API, но требует проверки типа при использовании (type assertion).
В итоге, интерфейсы в Go — это более гибкий и легковесный инструмент, способствующий слабой связанности (loose coupling) компонентов системы.