返回与跳转: break 与 continue
Kotlin 中存在 3 种跳出程序流程的表达式:
return
的默认行为是, 从最内层的函数或 匿名函数 中返回.
break
结束最内层的循环.
continue
在最内层的循环中, 跳转到下一次循环.
所有这些表达式都可以用作更大的表达式的一部分:
val s = person.name ?: return
这些表达式的类型都是 Nothing 类型.
Break 和 Continue 的位置标签
Kotlin 中的任何表达式都可以用 label 标签来标记. 标签由标识符后面加一个 @
符号构成, 比如 abc@
, fooBar@
. 要给一个表达式标记标签, 只需要将标签放在它之前.
loop@ for (i in 1..100) {
// ...
}
然后, 你就可以使用标签来限定 break
或 continue
的跳转对象:
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}
通过标签限定后, break
语句, 将会跳转到这个标签标记的循环语句之后. continue
语句则会跳转到循环语句的下一次循环.
使用标签控制 return 的目标
在 Kotlin 中, 通过使用字面值函数(function literal), 局部函数(local function), 以及对象表达式(object expression), 可以实现函数的嵌套. 通过标签限定的 return
语句, 可以从一个外层函数中返回.
最重要的使用场景是从 Lambda 表达式中返回. 如果需要从 Lambda 表达式返回, 可以对它标记一个标签, 然后使用这个标签来指明 return
的目标:
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // 局部的返回(local return), 返回到 Lambda 表达式的调用者: 返回到 forEach 循环
print(it)
}
print(" done with explicit label")
}
//sampleEnd
fun main() {
foo()
}
这样, return
语句就只从 Lambda 表达式中返回. 通常, 使用 隐含标签 会更方便一些, 因为隐含标签的名称与 Lambda 表达式被传递去的函数名称相同.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // 局部的返回(local return), 返回到 Lambda 表达式的调用者: 返回到 forEach 循环
print(it)
}
print(" done with implicit label")
}
//sampleEnd
fun main() {
foo()
}
另一种方法是, 你也可以使用 匿名函数 来替代 Lambda 表达式. 匿名函数内的 return
语句会从匿名函数内返回.
//sampleStart
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // 局部的返回(local return), 返回到匿名函数的调用者: 返回到 forEach 循环
print(value)
})
print(" done with anonymous function")
}
//sampleEnd
fun main() {
foo()
}
注意, 上面三个例子中局部返回的使用, 都与通常的循环中的 continue
关键字的使用很类似.
不存在与 break
直接等价的语法, 但可以模拟出来, 方法是增加一个嵌套的 Lambda 表达式, 然后在它内部使用非局部的返回:
//sampleStart
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // 非局部的返回(non-local return), 从传递给 run 函数的 Lambda 表达式中返回
print(it)
}
}
print(" done with nested loop")
}
//sampleEnd
fun main() {
foo()
}
当 return 语句指定了返回值时, 源代码解析器会将这样的语句优先识别为使用标签限定的 return 语句:
return@a 1
这里的含义是 "返回到标签 @a
处, 返回值为 1
", 而不是 "返回一个带标签的表达式 (@a 1)
".
最终更新: 2025/01/09