Kotlin 中有三个结构跳转表达式:
-
默认情况下,
return
会从最近的外层函数或匿名函数中返回。 -
break
会终止最近的循环 -
continue
会继续执行最近的外层循环的下一次迭代
这些表达式可以作为更大的表达式的一部分:
kotlin
val s = person.name ?: return
这些表达式是Nothing类型
Break and continue 标签
在 Kotlin 中所有的表达式都可以标记一个标签,标签由@
标记,比如abc@ 或者 fooBar@。使用的时候只需要把标签写在表达式的前面即可。
kotlin
loop@ for (i in 1..100) {
// ...
}
现在,可以使用标签来限定 break 或者 continue 的作用范围:
kotlin
loop@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@loop
}
}
用标签限定的 break 会跳转到被该标签标记的循环之后的执行点;而用标签限定的 continue 则会继续执行被该标签标记的循环的下一次迭代。
举个例子吧:
kotlin
outerLoop: for (let i = 0; i < 3; i++) {
console.log(`外层循环 i = ${i}`);
innerLoop: for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outerLoop; // 跳转到 outerLoop 循环之后
// continue outerLoop; // 直接进入 outerLoop 的下一次迭代(i 变为 2)
}
console.log(` 内层循环 j = ${j}`);
}
}
console.log("循环结束");
循环结束的时候 i 是 1,不是 2。
Return 标签
在 Kotlin,可以通过函数字面量、局部函数和对象表达式来实现函数嵌套。带限定符的 return 允许开发者从外层函数中返回。
带标签的返回最重要的使用场景是从 lambda 表达式返回。可以给 lambda 表达式添加标签,然后通过 return 来限定作用范围:
kotlin
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with explicit label")
}
//1245 done with explicit label
仅仅是return了lit
一般情况下,使用隐式标签会更便捷,因为这类标签与接收该 lambda 的函数同名。
kotlin
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with implicit label")
}
1245 done with implicit label
仅仅是return了forEach
当然了,也可以返回匿名函数,作用同上。
上面的局部 return 的用法,与常规循环中 continue 的作用类似。
目前没有与 break 直接对应的语法,但可以通过添加一个外层的 run lambda,并从该 lambda 中进行非局部返回来模拟 break 的效果:
kotlin
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // non-local return from the lambda passed to run
print(it)
}
}
print(" done with nested loop")
}
//12 done with nested loop
直接将loop返回
此处之所以能实现非局部返回,是因为嵌套的 forEach() 所接收的 lambda 是作为内联函数(inline function) 运行的。
当需要返回一个值时,语法解析器会优先识别带限定符的 return(qualified return)(即 return@标签名 形式),而非默认的穿透式 return。
kotlin
return@a 1
这意味着 "在标签 @a 处返回值 1",而非 "返回一个带标签的表达式 (@a 1)"。
kotlin
fun example() {
val result = listOf(1, 2, 3).map a@{ // map 会处理 lambda 的返回值
if (it == 2) {
return@a 100 // 在 @a 标签处返回 100(仅退出当前 lambda,作为 map 的转换结果)
}
it // 其他元素保持原值
}
println(result) // 输出:[1, 100, 3]
}