Внутренее устройство интерфейса, какое оно (структура iface, itab)?go-40

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

Структура iface

iface используется для интерфейсов, которые требуют реализации методов. Её определение выглядит примерно так:

type iface struct {
    tab  *itab          // Указатель на таблицу методов (itab)
    data unsafe.Pointer // Указатель на конкретные данные
}

Компоненты iface:

  1. tab *itab — содержит метаинформацию о типе и таблицу методов.
  2. data unsafe.Pointer — указатель на значение конкретного типа, реализующего интерфейс.

Структура itab

itab — это ключевая структура, связывающая интерфейс и конкретный тип:

type itab struct {
    inter *interfacetype // Метаинформация о интерфейсе
    _type *_type         // Метаинформация о конкретном типе
    hash  uint32         // Копия _type.hash для быстрых проверок типов
    _     [4]byte        // Выравнивание
    fun   [1]uintptr     // Таблица методов (гибкий массив)
}

Компоненты itab:

  1. inter *interfacetype — описывает сам интерфейс (например, его имя и сигнатуры методов).
  2. _type *_type — описывает конкретный тип, который реализует интерфейс.
  3. hash — кэш хеша типа, используется для проверок типа в type assertion.
  4. fun — массив указателей на методы конкретного типа, соответствующие методам интерфейса.

Структура eface

Пустой интерфейс не требует методов, поэтому его представление проще:

type eface struct {
    _type *_type         // Метаинформация о типе
    data  unsafe.Pointer // Указатель на данные
}

Разница между iface и eface:

  • iface используется для интерфейсов с методами.
  • eface — для пустого интерфейса interface{}.

Как работает приведение типов к интерфейсу?

  1. Компилятор проверяет, что тип реализует все методы интерфейса.
  2. Во время выполнения создается itab (или используется кэшированный), связывающий интерфейс и конкретный тип.
  3. Заполняется iface или eface:
    • data указывает на значение.
    • tab (для iface) ссылается на соответствующий itab.

Пример динамического поведения

var r io.Reader          // Интерфейс
r = os.Stdout            // Присваивание значения
b := r.(*os.File)        // Type assertion (использует itab.hash для проверки)

Резюмируем

  • Интерфейсы в Go представлены структурами iface (с методами) и eface (пустой интерфейс).
  • itab связывает интерфейс и конкретный тип, храня таблицу методов.
  • Динамическое поведение интерфейсов обеспечивается через itab и проверки во время выполнения.
  • Пустые интерфейсы (interface{}) работают через eface и не требуют таблицы методов.