Как передать функцию как параметр?

В Kotlin можно передавать функции как параметры в другие функции, потому что функции в языке являются «первоклассными объектами» (first-class citizens). Это значит, что их можно сохранять в переменные, передавать в качестве аргументов и возвращать из других функций.

Объявление функции, принимающей функцию в качестве параметра

Функции передаются с помощью функциональных типов. Синтаксис:

fun имяФункции(параметр: (типы_параметров) -> возвращаемый_тип) {
// тело
}

Пример:

fun operate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}

Здесь operation — это функция, принимающая два Int и возвращающая Int.

Вызов функции с передачей lambda

Вы можете передать lambda-выражение напрямую:

val result = operate(10, 5) { a, b -> a + b } // 15

Или определить lambda заранее:

val multiply = { a: Int, b: Int -> a \* b }
val result = operate(4, 5, multiply) // 20

Использование обычных функций как аргументов

Можно передавать именованные функции:

fun subtract(a: Int, b: Int): Int = a - b
val result = operate(10, 3, ::subtract) // 7

::subtract — это ссылка на функцию (function reference).

Пример с функцией без параметров

fun greet(action: () -> Unit) {
action()
}
fun sayHello() {
println("Hello!")
}
greet(::sayHello) // передаём ссылку на функцию
greet { println("Hi!") } // передаём lambda

Пример с возвращающим значением

fun processString(str: String, processor: (String) -> String): String {
return processor(str)
}
val upper = processString("kotlin") { it.uppercase() } // "KOTLIN"

Пример с несколькими параметрами

fun combine(a: String, b: String, combiner: (String, String) -> String): String {
return combiner(a, b)
}
val result = combine("Kotlin", "Rocks") { first, second -> "$first $second!" } // "Kotlin Rocks!"

Ссылки на методы и функции (function references)

Можно передавать методы классов и объектов через :::

fun printNumber(n: Int) {
println("Number: $n")
}
val numbers = listOf(1, 2, 3)
numbers.forEach(::printNumber)

Функции как переменные

Можно сохранять функции в переменные и использовать позже:

val add: (Int, Int) -> Int = { x, y -> x + y }
println(add(2, 3)) // 5

Можно использовать и ссылку на функцию:

fun divide(a: Int, b: Int): Int = a / b
val divOp: (Int, Int) -> Int = ::divide
println(divOp(10, 2)) // 5

Inline-функции и лямбда с возвращением

Если вы передаёте функцию как аргумент и хотите использовать return из неё — стоит использовать inline:

inline fun doIfTrue(condition: Boolean, action: () -> Unit) {
if (condition) action()
}
doIfTrue(true) {
println("Executed")
}

Без inline использовать return в лямбде, которая завершает внешнюю функцию, запрещено.

Типы параметров-функций

Функции можно типизировать:

  • () -> Unit — без параметров, ничего не возвращает

  • (Int) -> String — один Int, возвращает String

  • (String, Int) -> Boolean — два параметра, возвращает Boolean

Пример функции, принимающей такую сигнатуру:

fun check(value: String, condition: (String) -> Boolean): Boolean {
return condition(value)
}
val result = check("test") { it.length > 3 } // true

Передача функции как параметра в класс

Можно использовать лямбды в конструкторах:

class Task(val action: () -> Unit) {
fun run() = action()
}
val task = Task { println("Running task") }
task.run()

Тип с nullable-функцией

Иногда функция может быть опциональной:

fun executeIfNotNull(action: (() -> Unit)?) {
action?.invoke()
}

Пример: использование функций как параметров для фильтрации

fun filterList(list: List<Int>, predicate: (Int) -> Boolean): List<Int> {
return list.filter(predicate)
}
val filtered = filterList(listOf(1, 2, 3, 4, 5)) { it % 2 == 0 } // \[2, 4\]

В Kotlin функция может быть передана в качестве параметра в любом контексте: в функцию, в класс, в конструктор, в коллекцию, в качестве события или callback'а. Это позволяет строить гибкие и декларативные API.