В чем разница между пустой структурой (`struct{}`) и пустым интерфейсом (`interface{}` или `any`)?

Ответ

Это два совершенно разных по назначению и использованию типа в Go.

Пустая структура (struct{})

  • Память: Это тип данных, который не занимает памяти (0 байт).
  • Назначение: Используется как сигнал или маркер, когда значение не важно, а важно лишь само событие или наличие элемента.
  • Основные сценарии использования:
    1. Сигнализация в каналах: make(chan struct{}). Отправка в такой канал не передает никаких данных, а лишь сигнализирует о событии. Это самый дешевый способ синхронизации.
    2. Реализация множества (Set): В качестве значения в map, чтобы показать наличие ключа. mySet := make(map[string]struct{}). Проверка _, exists := mySet["key"] очень эффективна.

Пустой интерфейс (interface{} или any)

  • Память: Это не тип с нулевым размером. Переменная типа interface{} занимает 2 машинных слова (на 64-битной системе — 16 байт): одно слово для указателя на информацию о типе хранимого значения, второе — для указателя на само значение.
  • Назначение: Используется для хранения значения любого типа. Это основной инструмент для написания обобщенного кода (до появления дженериков в Go 1.18).
  • Основные сценарии использования:
    1. Функции общего назначения: Например, fmt.Println(a ...any) может принять и вывести любой тип данных.
    2. Работа с JSON: При декодировании JSON с неизвестной структурой данные часто помещаются в map[string]any.
    3. Хранение разнородных данных: В слайсе []any можно хранить числа, строки, структуры и т.д.

Для работы со значением, хранящимся в interface{}, требуется проверка типа (type assertion): val, ok := myInterface.(int).

Ключевое различие

  • struct{} — это конкретный тип без данных, используемый для экономии памяти и сигнализации.
  • interface{} (any) — это контейнер, который может хранить любой тип, но имеет накладные расходы на память и требует проверки типа для использования.