🧬 Generics: Как перестать писать Java на Go — 8 мая 2026 г. в 06:28:14.048
🧬 Generics: Как перестать писать Java на Go Мы ждали их 10 лет. И вот, когда они появились, код-ревью превратились в выставку угловых скобок. Я видел разработчиков, которые пытались впихнуть дженерики даже в хендлеры HTTP-запросов. Коллеги, давайте договоримся на берегу: Generics созданы для работы с типами, а не с поведением. Если вам нужно поведение, у нас уже есть интерфейсы. Давайте разберем, где дженерики это пушка, а где - технический долг. ❌ Как делать НЕ надо (Бизнес-логика) Типичная ошибка новичка - пытаться объединить несовместимое через any или огромные union типы, просто чтобы сэкономить пару строк. // 🤡 Ужасно: Пытаемся сделать "универсальное" сохранение func SaveToDB[T User | Order | Invoice](db *sql.DB, entity T) error { // И тут начинается ад из switch type или рефлексии } Почему это плохо? Потому что функция все равно должна знать детали каждой структуры, чтобы написать SQL-запрос. Дженерики тут не дают никакой пользы, только усложняют сигнатуру. Лечение: Используйте интерфейс Saver с методом Save(). ✅ Как надо (Структуры данных и Алгоритмы) Дженерики сияют там, где логике абсолютно плевать, какие данные внутри. Это коллекции (Set, Tree, Queue) и утилитарные функции (Filter, Map). // 🔥 Отлично: Функция фильтрации слайса func Filter[T any](slice []T, predicate func(T) bool) []T { var result []T for _, v := range slice { if predicate(v) { result = append(result, v) } } return result } // Использование: // evens := Filter([]int{1, 2, 3, 4}, func(v int) bool { return v%2 == 0 }) Мы написали это один раз, и оно работает с int, string, User и чем угодно. Больше никаких interface{} и кастов с паниками! ☝️ Нюанс для Senior-ов (Под капотом): Многие думают, что дженерики в Go работают как шаблоны в C++ (создают копию функции для каждого типа) или как в Java (Type Erasure). Go пошел своим путем: GCShape (Garbage Collection Shape). Компилятор группирует типы с одинаковым размером памяти и расположением указателей. Например, все указатели (*User, *Order) имеют одинаковый GCShape, и для них сгенерируется *только одна* версия функции под капотом, куда передастся невидимый словарь с метаданными. А вот для int и float64 сгенерируются разные версии. Итог: бинарник пухнет не так сильно, как в C++, а скорость работы почти как у обычных функций. А вы перешли на пакет samber/lo (Lodash для Go на дженериках) или по старинке пишете for руками? #golang #generics #cleancode #bestpractices 👉 @golang_lib

