Васильев Андрей Михайлович, 2024
Версии презентации
()
(Int) -> Int
fun doSome(value: Int, modifier: (Int) -> Int): Int {
val result: Int = modifier(value)
return result
}
Функциональный тип вызывается с помощью оператора invoke
modifier.invoke(55)
modifier(33)
(A, B) -> C
(Int, Double) -> String
— функциональный тип, принимающий два числа и
возвращающий строку() -> Unit
— функциональный тип, не принимающий никаких аргументов и
ничего не возвращающий. Unit
не может быть опущен(x: Int, y: Int) -> Point
null
-значения,
необходимо использовать круглые скобки: ((Int, Int) -> Int)?
typealias ClickHandler = (Button, ClickEvent) -> Unit
fun addClickHandler(handler: ClickHandler) { ... }
Если мы хотим создать новый блок кода, который можно сохранить (или передать):
{ a, b -> a + b}
fun(a: Int, b: Int): Int = a + b
В лямбда-выражении можно опустить типы, если компилятор сможет корректно их вывести относительно места их использования
val result = doSome(
34,
{ num -> num + 42 },
)
println(result)
Помимо создания нового блока можно создать ссылку на существующую функцию
Полная синтаксическая форма лямбда-выражений может быть представлена следующим образом:
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
{...}
->
Unit
, то в качестве возвращаемого типа
принимается последнее (а возможно и единственное) выражение внутри тела лямбдыЕсли вы вынесите все необязательные объявления, то, что останется, будет выглядеть следующим образом:
val sum = { x: Int, y: Int -> x + y }
return
Таким образом, два следующих фрагмента равнозначны:
ints.filter {
val shouldFilter = it > 0
shouldFilter
}
ints.filter {
val shouldFilter = it > 0
return@filter shouldFilter
}
ints.filter positive@{
val shouldFilter = it > 0
return@positive shouldFilter
}
return
без метки совершит выход из функции, не из лямбда-выражения
В Kotlin существует соглашение: если последний параметр функции является функцией, то лямбда-выражение, переданное в качестве соответствующего аргумента, может быть вынесено за круглые скобки
val product = items.fold(1) { acc, e -> acc * e }
Такой синтаксис также известен как trailing lambda
Когда лямбда-выражение является единственным аргументом функции, круглые скобки могут быть опущены
run { println("...") }
Стандартная библиотека по работе с коллекциями предлагает много функций, которые предполагают работу с лямбда-выражениями
it
— неявное имя единственного параметра
#
->
it
ints.filter { it > 0 } // этот литерал имеет тип '(it: Int) -> Boolean'
Если параметр лямбды не используется, то разрешено его имя заменить на символ подчёркивания
map.forEach { _, value -> println("$value!") }
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)
Обычно можно встретить в функциях-генераторах:
typealias Modifier = (Int) -> Int
fun createNumberAdder(howMuch: Int): Modifier = {
number + howMuch
}
invoke
typealias Modifier = (Int) -> Int
class NumberAdder(
private val howMuch: Int,
): Modifier {
override fun invoke(number: Int): Int {
return number + howMuch
}
}
val twoAdder = NumberAdder(2)
println(twoAdder(42)) // "44"
Чтобы объявить функциональный интерфейс, используйте модификатор fun.
fun interface KRunnable {
fun invoke()
}
Классы, которые его реализуют, должны будут реализовать только одну функцию
Рассмотрим следующий SAM-интерфейс по манипулированию целыми числами
fun interface IntManipulator {
fun manipulate(input: Int): Int
}
Реализуем этот интерфейс с помощью лямбда-выражения
val twoMultiplier = IntManipulator { it * 2 }
Реализуем этот интерфейс с помощью классов
class NumberMultiplier(private val multiplicator)
: IntManipulator {
override fun manipulate(input: Int) {
return input * multiplicator
}
}
val twoMultiplier = NumberMultiplier(2)
Функциональные интерфейсы и псевдонимы типов служат разным целям