Go: Дженерики
Теория: Типовые функции
В работе с коллекциями часто повторяется одна и та же логика: преобразовать все элементы, оставить только подходящие или свести список к одному значению. В других языках программирования для этого существуют стандартные функции map, filter и reduce. В Go их можно реализовать самостоятельно, а благодаря дженерикам — так, чтобы они работали с любыми типами.
Функция отображения Map получает срез элементов и функцию-преобразователь. Она создаёт новый срез, куда кладёт результат работы преобразователя для каждого элемента. Параметры типа T и R задают тип входных и выходных значений.
Если вызвать её так:
То каждый элемент будет возведён в квадрат. Та же функция работает и для строк, если преобразователь возвращает, например, длину:
Функция фильтрации Filter оставляет только те элементы, которые удовлетворяют условию. В сигнатуре параметр типа один, так как на входе и выходе остаются те же элементы.
Пример использования:
Та же логика работает и для строк:
Функция свёртки Reduce объединяет элементы среза в одно значение. Она принимает аккумулятор начального значения и функцию объединения. Тип аккумулятора R может совпадать с типом элементов или отличаться от него.
Примеры использования:
Такие обобщённые функции для коллекций дают сразу несколько преимуществ. Они устраняют дублирование кода, делают его выразительным и лаконичным. Строгая типизация сохраняется: компилятор знает, какие типы подставлены, и не позволит вызвать функцию с неподходящими аргументами. Производительность остаётся на уровне обычных циклов, потому что внутри нет приведения к interface{}.
Особую роль здесь играют замыкания. В примерах выше условия и преобразования описываются как функции, которые можно создавать прямо в месте вызова. Эти функции замыкают переменные внешнего окружения. Например:
Переменная threshold не передаётся в сигнатуре, но доступна внутри функции-предиката. Это делает код компактным и удобным: параметры типа описывают только структуру данных, а детали логики остаются на стороне замыканий.
В результате обобщённые реализации Map, Filter и Reduce становятся строительными блоками для работы с любыми коллекциями. Их можно комбинировать: сначала отфильтровать данные, затем преобразовать и в конце свести к одному результату. Всё это выполняется без дублирования, с полным контролем типов и в привычном для Go стиле.



