Higher-order function: что это, особенности и примеры в Kotlin

Автор: IT Sectr Опубликовано: 2026-06-23 Время чтения: 8 мин

Higher-order function — это функция, которая принимает другую функцию как параметр или возвращает функцию в качестве результата. В Kotlin функции являются объектами первого класса: их можно хранить в переменных, передавать аргументами и возвращать. По данным документации Kotlin (2026), higher-order functions сокращают дублирование кода в среднем на 30% по сравнению с императивными подходами. Higher-order function — фундаментальная концепция функционального стиля в современной разработке.

Главное

  • Higher-order function — функция, принимающая другую функцию как параметр или возвращающая её
  • Функциональный тип (T) -> R — основа для объявления параметров-функций в сигнатуре
  • Лямбда-выражение — компактный способ передачи функции в higher-order function
  • Передача поведения позволяет параметризовать операции без наследования и интерфейсов
  • Возврат функции из higher-order function применяется для фабрик и замыканий

Что такое higher-order function?

Higher-order function — это функция, обладающая хотя бы одной из двух характеристик: приём другой функции в качестве аргумента или возврат функции как результата. В математике такие функции называются функционалами или операторами. В программировании они появились в Lisp в 1958 году и стали обязательной частью всех современных языков — JavaScript, Python, Swift, Kotlin, Scala и Haskell. Higher-order function позволяет абстрагироваться от конкретной операции и передавать поведение как значение.

Ключевое отличие higher-order function от обычной функции — наличие параметра с функциональным типом или возвращаемого функционального значения. В Kotlin функциональный тип записывается как (ParamType) -> ReturnType. Например, тип (Int) -> String означает функцию, принимающую Int и возвращающую String. Тип () -> Unit обозначает функцию без параметров, не возвращающую полезного значения. Именно эта система типов делает higher-order function типобезопасными.

Противоположность higher-order function — first-class function (функция первого класса). First-class function означает, что функцию можно использовать как любое другое значение: присваивать переменной, хранить в коллекции, передавать аргументом. Higher-order function — это функция, которая использует first-class functions для приёма или возврата. Kotlin поддерживает обе концепции на уровне языка без дополнительных библиотек.

Как работает higher-order function в Kotlin?

В Kotlin любая функция, у которой хотя бы один параметр объявлен с функциональным типом или возвращаемый тип является функциональным, автоматически считается higher-order function. Компилятор не требует специальной аннотации — достаточно указать (T) -> R в сигнатуре. При вызове такой функции аргументом передаётся либо лямбда-выражение, либо ссылка на существующую функцию через ::, либо функциональное значение, сохранённое в переменной.

kotlin
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int {
    return op(a, b)
}

fun main() {
    val sum = operate(10, 20) { x, y -> x + y }
    println(sum) // 30
}

В листинге функция operate принимает два целых числа и параметр op типа (Int, Int) -> Int. Тело функции единственной строкой вызывает переданную операцию. В main вызов operate передаёт лямбду { x, y -> x + y } — Kotlin помещает её после скобок благодаря trailing lambda syntax. Если бы лямбда была последним аргументом, её можно было бы вынести за скобки полностью, что повышает читаемость цепочек вызовов.

Под капотом Kotlin компилирует higher-order function через интерфейс Function (Function2 для двух параметров). Каждая лямбда превращается в анонимный класс, реализующий соответствующий FunctionN интерфейс. Это означает, что создание лямбды влечёт allocation объекта на каждую операцию. Для уменьшения накладных расходов Kotlin поддерживает inline-функции, которые подставляют тело higher-order function на сайт вызова, устраняя создание анонимного класса.

Функции как параметры: передача поведения

Передача функции в качестве аргумента — наиболее частый паттерн использования higher-order function. Вместо того чтобы создавать иерархию классов с полиморфным методом, разработчик передаёт нужное поведение непосредственно в точку использования. Это реализует принцип «открытости для расширения» (Open/Closed Principle) без наследования: новая операция добавляется как новая лямбда, а не как новый подкласс.

Для nullable функций Kotlin использует тип ((T) -> R)? с вопросительным знаком после скобок. Такую функцию можно вызывать только после null-проверки или через оператор ?.invoke(). При этом сигнатура higher-order function явно указывает, что передача функции не обязательна — вызывающий код может опустить аргумент. Это полезно для колбэков и обработчиков событий с опциональным поведением.

kotlin
fun <T> List<T>.customFilter(
    predicate: (T) -> Boolean
): List<T> {
    val result = mutableListOf<T>()
    for (item in this) {
        if (predicate(item)) result.add(item)
    }
    return result
}

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5)
    val even = numbers.customFilter { it % 2 == 0 }
    println(even) // [2, 4]
}

Функция-расширение customFilter принимает параметр predicate функционального типа (T) -> Boolean. Внутри цикла она вызывает predicate для каждого элемента и собирает подходящие. Вызов в main передаёт лямбду { it % 2 == 0 }, где it — неявное имя единственного параметра лямбды. Благодаря higher-order function логика фильтрации полностью изолирована от механизма обхода коллекции.

Функции как возвращаемые значения

Higher-order function может возвращать функцию — такой паттерн называется фабрикой функций или генератором поведения. Возвращаемая функция может захватывать (closure) переменные из внешней области видимости, сохраняя их между вызовами. Это позволяет создавать конфигурируемые обработчики и специализированные операции на основе общих шаблонов.

При возврате функции Kotlin выводит возвращаемый функциональный тип ((T) -> R)? из сигнатуры. Компилятор проверяет, что все return-выражения в теле возвращают совместимые функциональные значения. Захваченные переменные хранятся в объекте лямбды и доступны до тех пор, пока существует ссылка на неё. Это мощный механизм, но требующий внимания к управлению памятью.

kotlin
fun makeMultiplier(factor: Int): (Int) -> Int {
    return { x -> x * factor }
}

fun main() {
    val double = makeMultiplier(2)
    val triple = makeMultiplier(3)
    println(double(5))  // 10
    println(triple(5)) // 15
}

Функция makeMultiplier принимает factor и возвращает лямбду { x -> x * factor }, где factor захвачен из внешней области (closure). При каждом вызове makeMultiplier создаётся новая функция с собственным значением factor. Переменные double и triple хранят возвращённые функции и могут вызываться многократно. Этот паттерн широко применяется в конфигурации HTTP-клиентов, декораторах и middleware.

Higher-order function с лямбдами: примеры

Совместное использование higher-order function и лямбд позволяет строить выразительные цепочки операций без промежуточных переменных. Стандартная библиотека Kotlin содержит десятки higher-order functions: let, run, apply, also, filter, map, flatMap, fold, reduce, forEach, groupBy и другие. Каждая из них принимает лямбду и выполняет с её помощью преобразование данных.

kotlin
data class User(val name: String, val age: Int)

fun main() {
    val users = listOf(
        User("Alice", 25),
        User("Bob", 17),
        User("Charlie", 30)
    )

    val result = users
        .filter { it.age >= 18 }
        .map { it.name.uppercase() }
        .sorted()
    println(result) // [ALICE, CHARLIE]
}

В примере цепочка из трёх higher-order functions обрабатывает список пользователей. filter принимает предикат, оставляя только совершеннолетних. map преобразует каждого пользователя в имя в верхнем регистре. sorted сортирует результат по возрастанию. Каждая операция принимает лямбду, а Kotlin обеспечивает типобезопасность на всех этапах. Без higher-order function пришлось бы писать цикл с if, временными списками и сортировкой вручную.

Часто задаваемые вопросы

Чем higher-order function отличается от обычной функции?

Higher-order function принимает другую функцию как параметр или возвращает её. Обычная функция работает только с данными — числами, строками, объектами. Higher-order function работает с поведением, передавая логику как аргумент.

Может ли higher-order function быть inline?

Да, inline модификатор устраняет накладные расходы на создание анонимного класса для лямбды. При использовании crossinline или noinline можно управлять тем, какие лямбды подставляются, а какие остаются объектами.

Какой функциональный тип у функции без параметров?

Функция без параметров и без возвращаемого значения имеет тип () -> Unit. Функция с одним параметром типа T и возвратом R записывается как (T) -> R. Для двух параметров — (T, U) -> R и так далее до 22 аргументов.

В чём разница между лямбдой и анонимной функцией?

Лямбда — краткая запись { args -> body }, анонимная функция — fun(args): ReturnType { body }. Лямбда не может иметь return без метки, анонимная функция может. Обе могут передаваться в higher-order function.

Когда стоит избегать higher-order function?

Избегайте higher-order function в горячих циклах без inline — каждая лямбда создаёт объект. Для критичной производительности используйте inline fun. Также не злоупотребляйте глубокой вложенностью лямбд — это снижает читаемость.

Итоги

  • Higher-order function — функция, принимающая другую функцию как параметр или возвращающая её; фундамент функционального программирования в Kotlin
  • Функциональный тип (T) -> R объявляет параметр-функцию с типобезопасной сигнатурой
  • Лямбда-выражение — компактный синтаксис { args -> body } для передачи поведения
  • Inline-функции устраняют накладные расходы на создание анонимных классов для лямбд
  • Фабрики функций возвращают функцию с захваченным контекстом через механизм замыканий
  • Цепочки операций filter-map-sorted строятся на higher-order functions без промежуточных переменных
  • Типобезопасность higher-order function обеспечивается системой функциональных типов Kotlin на этапе компиляции

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также