lambda
Kotlin 中的 Lambda 表达式和匿名函数有什么区别?
Lambda 表达式和匿名函数都是创建函数字面值的方式,但它们在语法和行为上有一些区别。
Lambda 表达式是最常用的方式,语法简洁,用花括号包围,参数和函数体用箭头分隔。Lambda 中的 return 语句会从包含它的函数返回,这是非局部返回(non-local return)。
匿名函数使用 fun 关键字但没有函数名,语法更像普通函数。匿名函数中的 return 只从匿名函数本身返回,这是局部返回(local return)。
// Lambda 表达式
val lambda = { x: Int, y: Int -> x + y }
// 匿名函数
val anonymousFunc = fun(x: Int, y: Int): Int {
return x + y
}
// return 行为的区别
fun testLambda() {
val list = listOf(1, 2, 3, 4, 5)
// Lambda:return 会从 testLambda 返回
list.forEach {
if (it == 3) return // 从 testLambda 返回
println(it)
}
println("这行不会执行")
}
fun testAnonymous() {
val list = listOf(1, 2, 3, 4, 5)
// 匿名函数:return 只从 forEach 返回
list.forEach(fun(value: Int) {
if (value == 3) return // 只从这个匿名函数返回
println(value)
})
println("这行会执行") // 输出:1 2 4 5 这行会执行
}
在实际开发中,Lambda 表达式用得更多,因为语法更简洁。匿名函数主要用在需要明确的局部返回语义的场景,或者需要显式指定返回类型的场景。
- 标签返回解决 Lambda 的返回问题
如果想在 Lambda 中实现局部返回,可以使用标签。给 Lambda 加上标签,然后用 return@标签 的方式返回。这样就不需要用匿名函数了。
fun testLabeledReturn() {
val list = listOf(1, 2, 3, 4, 5)
// 使用标签返回
list.forEach label@{
if (it == 3) return@label // 只从 Lambda 返回
println(it)
}
println("这行会执行")
// 隐式标签(函数名)
list.forEach {
if (it == 3) return@forEach // 使用函数名作为标签
println(it)
}
}
- 内联函数和非局部返回
Lambda 的非局部返回只在内联函数中允许。如果高阶函数没有 inline,Lambda 中不能使用非限定的 return。这是因为非内联函数的 Lambda 会被编译成类,无法从外层函数返回。这种限制保证了代码的正确性。
// 内联函数允许非局部返回
inline fun inlineFunc(block: () -> Unit) {
block()
}
// 非内联函数不允许
fun normalFunc(block: () -> Unit) {
block()
}
fun test() {
inlineFunc {
return // OK,因为是内联的
}
normalFunc {
// return // 编译错误
return@normalFunc // 必须用标签
}
}
- 类型推断的差异
Lambda 表达式的类型推断更智能,通常不需要显式声明参数类型。匿名函数有时需要显式声明返回类型,特别是有多个返回路径时。
// Lambda 类型推断
val list = listOf(1, 2, 3)
val doubled = list.map { it * 2 } // 类型自动推断
// 匿名函数可能需要显式类型
val result = list.map(fun(x): Int { // 显式返回类型
if (x > 2) return x * 2
return x
})
- 选择使用哪种方式
在实际开发中,大部分情况用 Lambda 表达式就够了,语法简洁、类型推断好。只有在以下情况考虑匿名函数:需要明确的局部返回语义、有多个返回路径、需要显式声明返回类型、代码逻辑复杂用 Lambda 不清晰时。在 Android 开发中,99% 的场景 Lambda 就足够了,匿名函数用得很少。
Android kotlin 替代 if...else... 语句,尾lambda写法
新建一个kt文件复制以下代码:
inline infix fun Boolean.trueLet(trueBlock: Boolean.() -> Unit): Else {
if (this) {
trueBlock()
return NotDoElse(this)
}
return DoElse(this)
}
inline infix fun Boolean.falseLet(falseBlock: Boolean.() -> Unit): Else {
if (!this) {
falseBlock()
return NotDoElse(this)
}
return DoElse(this)
}
interface Else {
infix fun elseLet(elseBlock: Boolean.() -> Unit)
}
class DoElse(private val boolean: Boolean) : Else {
override infix fun elseLet(elseBlock: Boolean.() -> Unit) {
elseBlock(boolean)
}
}
class NotDoElse(private val boolean: Boolean) : Else {
override infix fun elseLet(elseBlock: Boolean.() -> Unit) {
}
}
用法:
//原生写法
if (a > 1) {
println("执行操作")
}
//替代if写法
(a > 1).trueLet { println("执行操作") }
//原生写法
if (a != 1) {
println("执行操作")
}
//替代if写法
(a == 1).falseLet { println("执行操作") }
//原生写法
if (a < 1) {
println("执行true操作")
}else{
println("执行else操作")
}
//替代if写法
(a < 1).trueLet { println("执行true操作") }.elseLet { println("执行else操作") }