Структуры данных
Тема дорожной карты · Golang
Структуры данных в Go — строительные блоки для эффективной организации и управления данными; язык поставляется с несколькими мощными встроенными типами, покрывающими подавляющее большинство повседневных задач. Массивы ([N]T) имеют фиксированную длину на этапе компиляции, слайсы ([]T) — динамические представления на основе массивов, расширяемые через append, а словари (map[K]V) обеспечивают поиск по ключу за O(1) в среднем с помощью хеш-таблицы. Структуры позволяют определять составные типы с именованными полями, а встраивание даёт форму композиции, которая заменяет классическое наследование в идиоматичном Golang-коде. Стандартная библиотека расширяет эти примитивы пакетами container/list (двусвязный список), container/heap (интерфейс очереди с приоритетом) и container/ring (кольцевой буфер), а пакет sync предоставляет sync.Map для конкурентного доступа к ключ-значение без внешней блокировки. Для производительных Golang-приложений понимание расположения этих структур данных в памяти — выравнивание полей структур по кешлиниям, факторы роста ёмкости слайсов и коэффициенты загрузки словарей — ключевое условие написания эффективного кода с минимальной нагрузкой на GC.
Как это работает
Структуры данных покрывает встроенное: массивы (фиксированный размер — редко в идиоматичном Go), slices (динамические массивы — рабочая лошадка), maps (map[K]V, на хешах), strings (UTF-8 байтовые последовательности, неизменяемые). Struct — пользовательские типы с именованными полями; методы на типах (func (r Receiver) Method()); интерфейсы декларируют наборы методов (удовлетворяются неявно — нет ключевого слова implements). Указатели через & и *; slices и maps уже содержат указатели внутри.
Когда применять
Slices везде, где массивы соблазняют — почти всегда правильный ответ. Map — для lookup по ключу; помните, что Go-map не упорядочены. Embedding struct — для композиции (нет эквивалента наследования). Маленькие интерфейсы (1-3 метода) — Go-интерфейсы лучше когда обнаружены, чем объявлены (выносите, когда есть 2+ реализаций).
Типичные ошибки
Ловушки Структуры данных: slice-граблик — append(s, x) может или не может делить underlying массив с s (при реалокации не делит — тихие баги); for _, v := range slice { go func() { use(v) }() } захватывает v по ссылке до 1.22 (closures видят последнее значение — починено в 1.22, но многие туториалы до этого); nil-maps паникуют на запись (make(map[K]V)); огромные interface-типы убивают идиому "implicitly satisfied".