ZetCode

Kotlin lambda 表达式

最后修改于 2024 年 1 月 29 日

在本文中,我们将展示如何在 Kotlin 中使用 lambda 表达式。

一个 lambda 表达式 是一个匿名函数,它被视为一个值。 它可以绑定到一个变量,作为参数传递给一个函数,或者从一个函数返回。

val square: (Int) -> Int = { e: Int -> e * e }

在 Kotlin 中,lambda 表达式总是用大括号分隔。

Kotlin 匿名函数

匿名函数是没有名称的函数。

Main.kt
package com.zetcode

fun main() {

    val vals = intArrayOf(-2, -1, 0, 1, 2, 3, 4)

    val filtered = vals.filter(fun(e) = e > 0)
    println(filtered)
}

我们定义一个整数数组。 该数组使用 filter 函数进行过滤。 filter 函数将一个匿名函数作为参数。

val filtered = vals.filter(fun(e) = e > 0)

匿名函数用于过滤数组。

下一个示例使用 lambda 表达式重写了上一个示例。

Main.kt
package com.zetcode

fun main() {

    val vals = intArrayOf(-2, -1, 0, 1, 2, 3, 4)

    val filtered = vals.filter { e -> e > 0 }
    println(filtered)
}

在这里,我们使用大括号和 -> 运算符。

类型声明

在 lambda 表达式类型声明中,我们有一个方括号中的参数列表,后跟箭头 -> 运算符,然后是返回类型。

Main.kt
package com.zetcode

fun main() {

    val square: (Int) -> Int = { e: Int -> e * e }

    val r1 = square(5)
    val r2 = square(3)

    println(r1)
    println(r2)
}

在程序中,我们将一个 lambda 表达式绑定到一个值; 提供了完整的类型声明。

val square: (Int) -> Int = { e: Int -> e * e }

square 值绑定到一个 lambda 表达式,该表达式接受一个整数并返回一个整数。

类型推断

Kotlin 可以推断值的 数据类型,因此,我们可以省略一些声明。

Main.kt
package com.zetcode

fun main() {

    val square1: (Int) -> Int = { e: Int -> e * e }
    val square2 = { e: Int -> e * e }
    val square3: (Int) -> Int = { e -> e * e }
//    val square4 = { e -> e * e }

    val r1 = square1(5)
    val r2 = square2(3)
    val r3 = square3(6)

    println(r1)
    println(r2)
    println(r3)
}

在示例中,我们多次定义 square 函数。

val square1: (Int) -> Int = { e: Int -> e * e }

这是完整的类型声明。

val square2 = { e: Int -> e * e }

在这里,我们省略了 square2 名称的 lambda 声明。

val square3: (Int) -> Int = { e -> e * e }

在这种情况下,我们省略了 lambda 表达式中元素的声明。

//    val square4 = { e -> e * e }

但是,我们不能省略这两个声明。 此代码无法编译。


Unit 类型用于不返回值 的表达式。

Main.kt
package com.zetcode

fun main() {

    val l1 = { println("Hello there!") }
    val l2: (String) -> Unit = { name: String ->
        println("Hello $name!")
    }

    l1()
    l2("Lucia")
}

如果我们在控制台中打印某些内容,我们不会返回任何内容。 对于这种情况,我们指定 Unit

Kotlin lambda 表达式 it

it 是一个特殊的关键字,表示传递给 lambda 表达式的单个参数。

Main.kt
package com.zetcode

fun main() {

    val nums = listOf(1, 2, 3, 4, 5, 6)
    nums.forEach { println(it * 2) }
}

我们有一个整数列表。 使用 forEach,我们遍历元素列表并将它们乘以 2。

nums.forEach { println(it * 2) }

it 表示当前处理的项目。

将 lambdas 作为函数参数传递

在下面的示例中,我们将 lambda 表达式作为函数参数传递。

Main.kt
package com.zetcode

val inc = { e: Int -> e + 1 }
val dec = { e: Int -> e - 1 }
val square = { e: Int -> e * e }
val triple = { e: Int -> e * e * e }

fun doProcess(vals: List<Int>, f: (Int) -> Int) {

    val processed = vals.map { e -> f(e) }
    println(processed)
}

fun main() {

    val vals = listOf(1, 2, 3, 4, 5, 6)

    doProcess(vals, inc)
    doProcess(vals, dec)
    doProcess(vals, square)
    doProcess(vals, triple)
}

我们定义了四个 lambdas:incdecsquaretriple。 我们将 lambdas 传递给 doProcess 函数。

fun doProcess(vals: List<Int>, f: (Int) -> Int) {

    val processed = vals.map { e -> f(e) }
    println(processed)
}

我们为第二个参数提供类型声明:(Int) -> Int。 每个 lambda 接受一个整数并返回一个整数。

val processed = vals.map { e -> f(e) }

使用 map,我们在列表的每个元素上应用 lambda 表达式。

从 lambda 返回

lambda 中的最后一个表达式被返回。

Main.kt
package com.zetcode

val check = { u:Pair<String, Int> ->

    when (u.second) {
        in 0..75 -> "failed"
        else -> "passed"
    }
}

fun main() {

    val students =  listOf(

        Pair("Maria", 98),
        Pair("Pablo", 81),
        Pair("Lucia", 45),
        Pair("Peter", 98),
        Pair("Simon", 73),
    )

    students.forEach {

        val res = check(it)
        println("${it.first} has $res")
    }
}

在示例中,我们有一个学生列表。 我们检查哪些学生通过了考试。

val check = { u:Pair<String, Int> ->

    when (u.second) {
        in 0..75 -> "failed"
        else -> "passed"
    }
}

lambda 包含一个 when 表达式。 匹配的 arm 的值从 lambda 返回。

val res = check(it)
println("${it.first} has $res")

返回的值用于显示消息。

尾随 lambdas

如果函数的最后一个参数是一个函数,则 lambda 表达式可以放在括号之外。 如果 lambda 是唯一的参数,则可以完全省略括号。

Main.kt
package com.zetcode

data class User(val fname: String, val lname: String, val salary: Int)

fun main() {

    val users = listOf(
        User("John", "Doe", 1230),
        User("Lucy", "Novak", 670),
        User("Ben", "Walter", 2050),
        User("Robin", "Brown", 2300),
        User("Amy", "Doe", 1250),
        User("Joe", "Draker", 1190),
        User("Janet", "Doe", 980),
        User("Albert", "Novak", 1930)
    )

    val r1 = users.maxBy({ u: User -> u.salary })
    println(r1)

    val r2 = users.maxBy() { u: User -> u.salary }
    println(r2)

    val r3 = users.maxBy { u: User -> u.salary }
    println(r3)
}

在示例中,我们找到所有用户的最高工资。

val r1 = users.maxBy({ u: User -> u.salary })
println(r1)

在第一种情况下,我们将 lambda 表达式作为参数传递给 maxBy 函数。

val r2 = users.maxBy() { u: User -> u.salary }
println(r2)

由于 lambda 是最后一个参数,我们可以将其从括号中取出。

val r3 = users.maxBy { u: User -> u.salary }
println(r3)

由于 lambda 是唯一的参数,我们可以省略括号。

Kotlin 链接带有 lambdas 的函数

我们可以使用 lambda 表达式链接函数调用,创建简洁的代码。

Main.kt
package com.zetcode

fun main() {

    val words = listOf("sky", "cup", "water", "den", 
        "knife", "earth", "falcon")

    val res = words.filter { it.length == 5 }.sortedBy { it }
        .map { it.replaceFirstChar(Char::titlecase) }
    println(res)
}

我们过滤一个单词列表,对其进行排序,并将其元素大写。 所有这些都在一系列三个函数调用中完成。 这些函数具有尾随的 lambdas。

在 lambdas 中解构

参数可以在 lambda 表达式中解构。 对于未使用的变量,我们可以使用下划线 _ 字符。

Main.kt
package com.zetcode

fun main() {

    val words = mapOf(
        1 to "sky", 2 to "cup", 3 to "water", 4 to "den",
        5 to "knife", 6 to "earth", 7 to "falcon"
    )

    words.forEach { (_, v) -> println(v) }
}

我们有一个单词映射。 我们使用 forEach 遍历该映射。 该映射的每个元素都被解构为一个键/值对。 由于我们不使用键,因此我们使用下划线字符。

来源

高阶函数和 lambdas

在本文中,我们介绍了 Kotlin lambda 表达式。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出 所有 Kotlin 教程