В чем ключевые различия между интерфейсами в Go и интерфейсами в языках вроде Java или C#?

Ответ

Интерфейсы в 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) как часть публичного контракта библиотеки или модуля.