Lambda:什么是 Lambda,语法及在 Kotlin 中的使用

作者: IT Sectr 发布日期: 2026-06-23 阅读时间: 7 分钟

Lambda — 是一种匿名函数,以紧凑表达式 { 参数 -> 体 } 的形式呈现。在 Kotlin 中,lambda 是将行为传递给高阶函数(higher-order functions)的主要方式,提供了简洁的语法,无需声明单独的函数。根据 Kotlin 文档(2026),典型项目中超过 70% 的高阶函数都是通过 lambda 调用的。Lambda 允许以函数式风格编写代码,语法噪音最小。

要点

  • Lambda — 语法为 { args -> body } 的匿名函数,没有名称
  • 隐式名称 it 替代 lambda 的唯一参数,简化写法
  • Trailing lambda — 将最后一个 lambda 移出调用括号以提高可读性
  • 捕获(closure) — lambda 可以访问外部作用域中的变量
  • 函数类型 (T) -> R 定义 lambda 的签名并由编译器检查

什么是 lambda?

Lambda(lambda 表达式)— 是一种定义为表达式而非声明的匿名函数。该术语源于 Alonzo Church(1936)的 lambda 演算。在编程中,lambda 代表一个代码块,可以作为值传递、存储在变量中并稍后调用。在 Kotlin 中,lambda 始终用花括号 { } 括起来,参数用箭头 -> 与体分隔。

Lambda 与普通函数的不同之处在于没有名称和 fun 关键字。这允许在使用点直接声明行为,而不会用额外的声明使代码变得杂乱。Kotlin 编译器从上下文中推断参数类型,因此在许多情况下可以省略类型。Lambda 是函数类型 (T) -> R 之上的语法糖:每个 lambda 都有对应的函数类型。

Lambda 在 Kotlin 中的主要应用是传递给高阶函数(higher-order functions)。标准库到处使用 lambda:filter { it > 0 }、map { it.uppercase() }、forEach { println(it) }。Lambda 还用于创建事件监听器、回调、通过 apply 和 run 创建对象配置器,与匿名类相比使代码更加声明式。

Kotlin 中 lambda 表达式的语法

Kotlin 中lambda 表达式的完整形式:{ 参数 -> lambda_体 }。参数用逗号列出,后跟箭头和体 — 一个或多个表达式。如果体包含多行,最后一个表达式成为返回值。如果函数接受 lambda 作为最后一个参数,可以将其移出调用括号。

kotlin
val sum: (Int, Int) -> Int = { a, b -> a + b }

// 从上下文推断的类型
val sumShort = { a: Int, b: Int -> a + b }

// Lambda 调用
val result = sum(5, 3)  // 8
println(result)

变量 sum 以显式函数类型 (Int, Int) -> Int 声明,并用 lambda { a, b -> a + b } 初始化。对于 sumShort,类型在 lambda 内部指定,变量类型被推断。两种变体等效。调用 lambda 与调用普通函数没有区别 — 使用 sum(5, 3) 语法。无参数的 lambda 写为 { body },带一个参数的 — { it -> it * 2 } 或简单地 { it * 2 }。

隐式名称 it 和省略参数

当 lambda 正好接受一个参数时,Kotlin 提供隐式名称 it。这消除了在左侧声明参数的需要。程序员只需编写 lambda 体,使用 it 访问唯一参数。这种语法在集合处理链中特别方便,其中 it 表示当前元素。

kotlin
val numbers = listOf(1, 2, 3, 4, 5)

// 显式参数名
val squaredExplicit = numbers.map { n -> n * n }

// 隐式 it
val squared = numbers.map { it * it }

// 使用 it 过滤
val even = numbers.filter { it % 2 == 0 }

println(squared) // [1, 4, 9, 16, 25]

在示例 map { it * it } 中,使用 it 代替声明 n ->。Kotlin 自动为 lambda 的唯一参数分配 it。如果 lambda 接受两个或更多参数,则不会创建 it — 必须显式声明所有参数。为了提高嵌套 lambda 的可读性,建议给参数赋予有意义的名称,并在简短的单行谓词中使用 it。

Trailing lambda 和多行 lambda

Trailing lambda(尾随 lambda)— Kotlin 的语法特性,允许将最后一个参数 lambda 放在函数调用的圆括号之外。这使代码类似于内置的语言构造。如果 lambda 是唯一参数,可以完全省略括号。这种方法在标准库和 DSL 中被积极使用。

kotlin
// 标准调用
thread(block = {
    println("来自线程的问候")
})

// Trailing lambda 版本
thread {
    println("来自线程的问候")
}

// 使用 trailing lambda 的 repeat
repeat(3) { index ->
    println("迭代 $index")
}

// 使用多行 lambda 的 run
val config = run {
    val host = "localhost"
    val port = 8080
    "$host:$port"
}

Thread 函数接受 Runnable 作为最后一个参数。得益于 trailing lambda,lambda 可以放在括号之外传递,视觉上类似于代码块。Repeat 函数接受迭代次数和带索引的 lambda。Run — 是高阶函数的例子,其中多行 lambda 计算由最后一个表达式返回的值。如果 lambda 是唯一参数,可以省略 run() 周围的括号。

Lambda 中的变量捕获(closure)

变量捕获(closure)— lambda 访问在外部作用域中声明的变量的能力。在 Kotlin 中,lambda 可以读取和修改 var 变量,以及从周围上下文中读取 val 变量。捕获的变量在其整个生命周期中与 lambda 一起存储,从而允许创建带状态的函数。

kotlin
fun makeCounter(): () -> Int {
    var count = 0
    return {
        count++  // 捕获次数
    }
}

fun main() {
    val counter = makeCounter()
    println(counter()) // 0
    println(counter()) // 1
    println(counter()) // 2
}

MakeCounter 函数声明一个局部变量 count 并返回 lambda { count++ }。尽管 makeCounter 已完成其工作,返回的 lambda 通过闭包(closure)保持对 count 的引用。每次调用 counter() 都会增加并返回当前值。Closure 机制构成了柯里化、函数工厂和记忆化的基础。重要的是要记住,捕获可变的变量可能在并行执行中导致意外行为。

常见问题

Lambda 可以有 return 吗?

Lambda 不支持无条件的 return — 没有标签的 return 将控制权返回给外部函数。要从 lambda 退出,请使用 return@label,其中 label 是 lambda 被传递到的那个高阶函数的名称。

Lambda 和匿名函数有什么区别?

匿名函数 写为 fun(a: Int): Int { return a * 2 } 并支持没有标签的 return。Lambda { a -> a * 2 } 语法上更简短,但提前退出需要 return@label。

如何将不带箭头的 lambda 作为参数传递?

如果 lambda 不接受参数,箭头被省略:{ body() }。如果接受一个参数但不使用它,则写 { _ -> body() } 并用下划线忽略参数。

Lambda 总是创建新对象吗?

是的,每个传递给非内联函数的 lambda 都会创建一个匿名类实例。对于内联函数,lambda 在调用点内联而不创建对象。非捕获(non-capturing)lambda 被缓存在单例对象中。

为什么不能在 lambda 中直接使用 return?

Return 在 Kotlin 中是一个跳转运算符,属于最近的带 fun 的函数。Lambda 不是函数(fun),而是表达式。因此,lambda 内部不带标签的 return 被视为从外部包围函数的返回。

总结

  • Lambda — 语法为 { args -> body } 的匿名函数,作为值传递给高阶函数
  • 隐式名称 it 替代唯一参数,在短谓词中使代码更紧凑
  • Trailing lambda 将最后一个 lambda 移出调用括号,作为代码块阅读
  • 捕获(closure) 允许 lambda 在包围函数完成后访问外部上下文中的变量
  • 函数类型 (T) -> R 在编译阶段定义 lambda 的签名并进行检查
  • 内联函数 消除为 lambda 创建匿名类,提高循环中的性能
  • 多行 lambda 返回最后一个表达式的值,支持复杂计算而无需声明单独的函数

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读