В Go тип struct{} представляет собой структуру без полей и занимает 0 байт памяти. Это ценная особенность, используемая для минимизации потребления ресурсов в тех случаях, когда важен факт наличия чего-то, но не нужны данные — к примеру, в реализации множеств (set), структур-сигнализаторов или каналов для событий.
Пример использования для множества:
mySet := make(map[string]struct{}) mySet["foo"] = struct{}{} if _, ok := mySet["foo"]; ok { fmt.Println("foo присутствует в mySet") }
struct{} используется как значение, чтобы показать присутствие ключа.map[string]bool, вариант с struct{} экономичнее по памяти.Каналы для сигнализации:
done := make(chan struct{}) // Горутина ждет сигнала завершения <-done
Чем отличается map[string]struct{} от map[string]bool при реализации множества? Почему map[string]struct{} предпочтительнее и есть ли у него минусы?
Ответ:
map[string]struct{} использует 0 байт на значение, самый компактный вариант — экономится память, особенно при большом количестве данных.map[string]bool требует 1 байта на значение (внутренне всё равно может занимать больше памяти из-за выравнивания).map[string]struct{}: нельзя быстро получить список всех значений, помеченных true, если вдруг потребуется логическое значение. Всё равно перебор по ключам.Пример:
set := make(map[string]struct{}) set["Alice"] = struct{}{} _, exists := set["Alice"] // true flags := make(map[string]bool) flags["Alice"] = true _, exists := flags["Alice"] // true
История
В проекте для хранения уникальных идентификаторов использовали map[string]bool, что с увеличением данных привело к значительному росту потребления памяти — сотни мегабайт в сравнении с вариантом на map[string]struct{}. Перевод на struct{} уменьшил расход памяти более чем вдвое.
История
Новичок сигнализировал о завершении горутины через
chan bool. При большом количестве горутин передача значения oказалась избыточной: нигде не анализировалось, пришелtrueилиfalse. Замена наchan struct{}показала архитектурную неточность и позволила упростить код.
История
В библиотеке делали множество через map, где в качестве значения использовали string. Это занимало слишком много памяти. После Code Review перевели на map[тип]struct{}. Ошибка обнаружилась после анализа профиля памяти при нагрузочном тестировании, когда приложение падало по OOM.