Васильев Андрей Михайлович, 2024
Версии презентации
()(Int) -> Intfun 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) -> Pointnull-значения,
необходимо использовать круглые скобки: ((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 — неявное имя единственного параметра
#
->itints.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
}invoketypealias 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)Функциональные интерфейсы и псевдонимы типов служат разным целям