Интерфейсы в Go — это абстрактные типы, определяющие набор методов, которые должны быть реализованы конкретными типами. Внутренне они представлены двумя основными структурами: iface
и eface
.
iface
используется для интерфейсов, которые требуют реализации методов. Её определение выглядит примерно так:
type iface struct {
tab *itab // Указатель на таблицу методов (itab)
data unsafe.Pointer // Указатель на конкретные данные
}
tab *itab
— содержит метаинформацию о типе и таблицу методов.data unsafe.Pointer
— указатель на значение конкретного типа, реализующего интерфейс.itab
— это ключевая структура, связывающая интерфейс и конкретный тип:
type itab struct {
inter *interfacetype // Метаинформация о интерфейсе
_type *_type // Метаинформация о конкретном типе
hash uint32 // Копия _type.hash для быстрых проверок типов
_ [4]byte // Выравнивание
fun [1]uintptr // Таблица методов (гибкий массив)
}
inter *interfacetype
— описывает сам интерфейс (например, его имя и сигнатуры методов)._type *_type
— описывает конкретный тип, который реализует интерфейс.hash
— кэш хеша типа, используется для проверок типа в type assertion
.fun
— массив указателей на методы конкретного типа, соответствующие методам интерфейса.Пустой интерфейс не требует методов, поэтому его представление проще:
type eface struct {
_type *_type // Метаинформация о типе
data unsafe.Pointer // Указатель на данные
}
iface
используется для интерфейсов с методами.eface
— для пустого интерфейса interface{}
.itab
(или используется кэшированный), связывающий интерфейс и конкретный тип.iface
или eface
:
data
указывает на значение.tab
(для iface
) ссылается на соответствующий itab
.var r io.Reader // Интерфейс
r = os.Stdout // Присваивание значения
b := r.(*os.File) // Type assertion (использует itab.hash для проверки)
iface
(с методами) и eface
(пустой интерфейс).itab
связывает интерфейс и конкретный тип, храня таблицу методов.itab
и проверки во время выполнения.interface{}
) работают через eface
и не требуют таблицы методов.