ПрограммированиеGo Backend разработчик

Что такое интерфейсы в Go, как происходит их реализция и сравнение, и в чем их отличие от интерфейсов в других языках?

Проходите собеседования с ИИ помощником Hintsage

Ответ

Интерфейсы в Go — это набор методов, которые должен реализовать тип для соответствия этому интерфейсу. Нет явного ключевого слова implements: совместимость структурная, а не декларативная. Присваивание реализующего типа переменной интерфейсного типа возможно только если тип реализует все методы интерфейса.

Важно: интерфейсная переменная содержит два указателя — на данные (value) и на тип (type).

Пример объявления и реализации:

type Printer interface { Print() } type MyPrinter struct{} func (mp MyPrinter) Print() { fmt.Println("printing...") } var p Printer = MyPrinter{} p.Print() // "printing..."

Вопрос с подвохом

Что произойдет, если интерфейсная переменная равна nil? Чем отличается "var i interface{} = nil" от "var i interface{}"?

Частый неверный ответ — "оба значения — nil". На самом деле — нет:

  • var i interface{} = nil — переменная действительно nil (type=nil, value=nil)
  • Но если var p *MyPrinter = nil; var i Printer = p, то i != nil, потому что type != nil (внутри i — type=*MyPrinter, value=nil), и многие проверки наподобие if i == nil не сработают, когда ожидаете.

Пример:

var p *MyPrinter = nil var i Printer = p fmt.Println(i == nil) // false!

Примеры реальных ошибок из-за незнания тонкостей темы


История

Описание: В одном сервисе обработчик ошибок возвращал интерфейс с nil-значением, и клиенты считали ошибку ненулевой, вызывая избыточные действия. Проблема была в сравнении интерфейса с nil.


История

Описание: При написании тестов ошибочно проверяли ошибку интерфейсного типа на равенство nil после возврата структуры с nil-полями. Тесты не детектировали настоящие ошибки, что привело к появлению бага на проде.


История

Описание: При миграции с одного интерфейсного типа на другой забыли реализовать все методы нового интерфейса, т.к. не было явного implements. Код компилировался, но интерфейс не реализовывался, некоторые мокающиеся функции перестали работать.