Ответ
Интерфейсы в Go и в языках типа Java/C# служат одной цели — определению контракта (поведения), но делают это по-разному.
1. Реализация: Неявная (Go) vs. Явная (Java/C#)
Это самое главное различие.
-
Go: Тип удовлетворяет интерфейсу неявно, если он реализует все его методы. Не нужно ключевого слова
implements
. Это называется "утиной типизацией" (duck typing).type Reader interface { Read(p []byte) (n int, err error) } // MyReader неявно удовлетворяет интерфейсу Reader. type MyReader struct{} func (r MyReader) Read(p []byte) (int, error) { /* ... */ return 0, nil }
- Java/C#: Класс должен явно указать, что он реализует интерфейс.
// Класс должен явно указать "implements Reader" class MyReader implements Reader { @Override public int read(byte[] p) { /* ... */ return 0; } }
2. Содержимое интерфейса
- Go: Интерфейс может содержать только сигнатуры методов. Он не может иметь полей, констант или реализаций методов.
- Java/C#: Современные версии интерфейсов могут содержать не только сигнатуры, но и:
- Методы с реализацией по умолчанию (
default
методы в Java). - Статические методы и поля.
- Приватные методы.
- Методы с реализацией по умолчанию (
3. Пустой интерфейс interface{}
- Go: Имеет специальный тип — пустой интерфейс
interface{}
(или его псевдонимany
с Go 1.18). Он не содержит методов, поэтому ему удовлетворяет любой тип данных. Это основной способ работы с данными неизвестного типа в Go.func PrintAnything(v interface{}) { fmt.Println(v) }
- Java/C#: Прямого аналога нет. Ближайшим является базовый класс
Object
(Java) илиobject
(C#), от которого наследуются все типы, но это концептуально иная вещь (наследование, а не реализация интерфейса).
4. Философия использования
- Go: "Принимай интерфейсы, возвращай структуры". Интерфейсы часто определяются на стороне потребителя (consumer), чтобы описать, какое поведение ему нужно. Это способствует сильной декомпозиции.
- Java/C#: Интерфейсы чаще определяются на стороне поставщика (provider) как часть публичного контракта библиотеки или модуля.