Лямбда-выражения

Последнее обновление: 26.05.2021

Лямбда-выражения представляют небольшие кусочки кода, которые выполняют некоторые действия. Фактически лямбды преставляют сокращенную запись функций. При этом лямбды, как и обычные и анонимные функции, могут передаваться в качестве значений переменным и параметрам функции.

Лямбда-выражения оборачиваются в фигурные скобки:

{println("hello")}

В данном случае лямбда-выражение выводит на консоль строку "hello".

Лямбда-выражение можно сохранить в обычную переменную и затем вызывать через имя этой переменной как обычную функцию.

fun main() {

	val hello = {println("Hello Kotlin")}
	hello()
	hello()
}

В данном случае лямбда сохранена в переменную hello и через эту переменную вызывается два раза. Поскольку лямбда-выражение представляет сокращенную форму функции, то переменная hello имеет тип функции () -> Unit.

val hello: ()->Unit = {println("Hello Kotlin")}

Также лямбда-выражение можно выполнить сразу при определении с помощью оператора run:

fun main() {

    run {println("Hello Kotlin")}
}

Либо можно запускать как обычную функцию, используя круглые скобки:

fun main() {

    {println("Hello Kotlin")}()
}

Следует учитывать, что если до подобной записи идут какие-либо инструкции, то Kotlin автоматически может не определять, что определения лямбда-выражения составляет новую инструкцию. В этом случае предыдущую инструкции можно завершить точкой с запятой:

fun main() {

    {println("Hello Kotlin")}();
    {println("Kotlin on Metanit.com")}()
}

Передача параметров

Лямбды как и функции могут принимать параметры. Для передачи параметров используется стрелка ->. Параметры указываются слева от стрелки, а тело лямбда-выражения, то есть сами выполняемые действия, справа от стрелки.

fun main() {

    val printer = {message: String -> println(message)}
    printer("Hello")
    printer("Good Bye")
}

Здесь лямбда-выражение принимает один параметр типа String, значение которого выводится на консоль. Переменная printer в данном случае имеет тип (String) -> Unit.

При вызове лямбда-выражения сразу при его определении в скобках передаются значения для его параметров:

fun main() {

    {message: String -> println(message)}("Welcome to Kotlin")
}

Если параметров несколько, то они передаются слева от стрелки через запятую:

fun main() {

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

Если в лямбда-выражении надо выполнить не одно, а несколько действий, то эти действия можно размещать на отдельных строках после стрелки:

val sum = {x:Int, y:Int ->
	val result = x + y
	println("$x + $y = $result")
}

Возвращение результата

Выражение, стоящее после стрелки, определяет результат лямбда-выражения. И этот результат мы можем присвоить, например, переменной.

Если лямбда-выражение формально не возвращает никакого результата, то фактически, как и в функциях, возвращается значение типа Unit:

val hello = { println("Hello")}
val h = hello()             // h представляет тип Unit

val printer = {message: String -> println(message)}
val p = printer("Welcome")    // p представляет тип Unit

В обоих случаях используется функция println, которая формально не возвращает никакого значения (точнее возвращает объект типа Unit).

Но также может возвращаться конкретное значение:

fun main() {

    val sum = {x:Int, y:Int -> x + y}
	
    val a = sum(2, 3)   // 5
    val b = sum(4, 5)   // 9
    println("a=$a  b=$b")
}

Здесь выражение справа от стрелки x + y продуцирует новое значение - сумму чисел, и при вызове лямбда-выражения это значение можно передать переменной. В данном случае лямбда-выражение имеет тип (Int, Int) -> Int.

Если лямбда-выражение многострочное, состоит из нескольких инструкций, то возвращается то значение, которое генерируется последней инструкцией:

val sum = {x:Int, y:Int ->
	val result = x + y
	println("$x + $y = $result")
	result
}

Последнее выражение по сути представляет число - сумму чисел x и y и оно будет возвращаться в качестве результата лямбда-выражения.

Лямбда-выражения как аргументы функций

Лямбда-выражения можно передавать параметрам функции, если они представляют один и тот же тип функции:

fun main() {

    val sum = {x:Int, y:Int -> x + y }
    doOperation(3, 4, sum)                      	// 7
    doOperation(3, 4, {a:Int, b: Int -> a * b}) // 12

}
fun doOperation(x: Int, y: Int, op: (Int, Int) ->Int){

    val result = op(x, y)
    println(result)
}

Типизиция параметров лямбды

При передаче лямбды параметру или переменной, для которой явным образом указан тип, мы можем опустить в лямбда-выражении типы параметров:

fun main() {
    val sum: (Int, Int) -> Int = {x, y -> x + y } 
    doOperation(3, 4, {a, b -> a * b})
}
fun doOperation(x: Int, y: Int, op: (Int, Int) ->Int){

    val result = op(x, y)
    println(result)
}

Здесь в случае с переменной sum Kotlin видит, что ее тип (Int, Int) -> Int, то есть и первый, и второй параметр представляют тип Int. Поэтому при присвоении переменной лямбды {x, y -> x + y } Kotlin автоматически поймет, что параметры x и y представляют именно тип Int.

То же самое касается и вызова функции doOperation() - при передаче в него лямбды Kotlin автоматически поймет какой параметр какой тип представляет.

trailing lambda

Если параметр, который принимает функцию, является последним в списке, то при передачи ему лямбда-выражения, саму лямбду можно прописать после списка параметров. Например, возьмем выше использованную функцию doOperation():

fun doOperation(x: Int, y: Int, op: (Int, Int) ->Int){

    val result = op(x, y)
    println(result)
}

Здесь параметр, который представляет функцию - параметр op, является последним в списке параметров. Поэтому вместо того, чтобы написать так:

doOperation(3, 4, {a, b -> a * b}) // 12

Мы также можем написать так:

doOperation(3, 4) {a, b -> a * b} // 12

То есть вынести лямбду за список параметров. Это так называемая конечная лямбда или trailing lambda

Возвращение лямбда-выражения из функции

Также фукция может возвращать лямбда-выражение, которое соответствует типу ее возвращаемого результата:

fun main() {
    val action1 = selectAction(1)
    val result1 = action1(4, 5)
    println(result1)        // 9

    val action2 = selectAction(3)
    val result2 = action2(4, 5)
    println(result2)        // 20

    val action3 = selectAction(9)
    val result3 = action3(4, 5)
    println(result3)        // 0
}
fun selectAction(key: Int): (Int, Int) -> Int{
    // определение возвращаемого результата
    when(key){
        1 -> return {x, y -> x + y }
        2 -> return {x, y -> x - y }
        3 -> return {x, y -> x * y }
        else -> return {x, y -> 0 }
    }
}

Неиспользуемые параметры

Обратим внимание на предыдущий пример на последнюю лямбду:

else -> return {x, y -> 0 }

Если в функцию selectAction() передается число, отличное от 1, 2, 3, то возвращается лямбда-выражение, которое просто возвращает число 0. С одной стороны, это лямбда-выражение должно соответствовать типу возвращаемого результата функции selectAction() - (Int, Int) -> Int

С другой стороны, оно не использует параметры, эти параметры не нужны. В этом случае вместо неиспользуемых параметров можно указать прочерки:

else -> return {_, _ -> 0 }
Помощь сайту
WebMoney
  • P378451176208
  • Z280152397659
ЮMoney/Яндекс-Деньги
  • 410011174743222
PayPal
  • metanit22@mail.ru
Перевод на карту
  • Номер карты: 4048415020898850