Go: Дженерики
Теория: Введение
До версии Go 1.18 программистам приходилось выбирать: либо дублировать один и тот же алгоритм под разные типы данных, либо использовать пустой интерфейс interface{} и терять безопасность типов и скорость. Дженерики решили эту проблему. Теперь можно писать универсальные функции и структуры, которые работают с разными типами данных, сохраняя строгую типизацию.
Зачем нужны дженерики
Представим задачу поиска максимума в срезе. Для []int мы бы писали одну функцию, для []float64 — другую, для []string — третью. Логика одинакова, но код разный. С дженериками алгоритм можно описать один раз и применять ко всем.
Без дженериков — три функции
Здесь три функции делают одно и то же, различается только тип входных данных.
Решение с дженериками
Что здесь важно:
T— параметр типа, который подставляется компилятором автоматически.comparable— ограничение, которое гарантирует, что для типаTдоступны операции сравнения.- Вместо трёх функций теперь достаточно одной.
Синтаксис дженериков в Go
Когда программист знакомится с дженериками, первое, что бросается в глаза, — это квадратные скобки []. Именно там указываются параметры типа. Дальше этот параметр можно использовать внутри функции, структуры или метода так же, как обычный тип (int, string и т. д.).
Функции с дженериками
Начнём с простого примера. Автор описывает функцию Print, которая умеет печатать значения любого типа.
Функция одна, но работает и с числами, и со строками. Если бы не было дженериков, пришлось бы писать PrintInt, PrintString и так далее.
Несколько параметров
Затем разработчик сталкивается с ситуацией, когда нужно работать с разными типами сразу. Для этого можно указать несколько параметров.
Теперь одна функция умеет принимать и числа, и строки, и любые другие комбинации.
Ограничения (constraints)
Но что если внутри функции нужно использовать операции сравнения или сложения? Просто any не подойдёт. Здесь на помощь приходят ограничения.
В этом коде Go строго проверяет: если тип нельзя сравнивать, программа даже не скомпилируется.
Свои ограничения
Иногда стандартных ограничений мало. Тогда создают собственные интерфейсы.
Таким образом, программист задаёт допустимый набор типов, и компилятор будет следить, чтобы никто не подсунул, например, строку.
Дженерики в структурах
Дальше становится интереснее. Параметры типа можно использовать и в структурах. Возьмём простой пример — коробку, которая умеет хранить значение любого типа.
Структура одна, но работает и с числами, и со строками. Тип указывается один раз при создании коробки.
Методы с дженериками
Методы у структур ничем не отличаются от обычных функций. Они так же могут использовать параметр типа.
Здесь мы написали универсальный контейнер один раз, и он сразу работает для любых типов.
Итоги
Синтаксис дженериков в Go устроен просто и логично. Параметры типа указываются в квадратных скобках, а внутри функций и структур они ведут себя как обычные типы. Ограничения позволяют контролировать, что именно разрешено делать с данными: сравнивать, складывать или просто хранить. Всё это даёт возможность писать универсальные алгоритмы и структуры без копипаста, сохраняя безопасность типов и высокую производительность.



