Kotlin 控制流(二):返回和跳转

Kotlin 控制流(一):条件和循环

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]
}

原文

相关推荐
文人sec4 小时前
MySQL主库出问题了,从库怎么办?备库为什么会延迟好几个小时?
android·数据库·mysql
hai_android4 小时前
不用 AIDL,手把手教你手写 Binder 代理类
android·kotlin
mmsx5 小时前
osmdroid 地图实战 03|地图的"分层世界":离线方案、图层模型与 Overlay 体系
android·前端
张文是假的啊6 小时前
IOC依赖注入问题:@Primary 和 @Qualifier的使用
android
换元不配限6 小时前
ConstraintLayout核心用法详解(三):引导线、屏障、组和占位
android·placeholder·barrier·约束布局·guideline
雨白7 小时前
Kotlin 泛型进阶:攻克型变与实化,直击痛点
kotlin
心平气和量大福大8 小时前
android studio(AS)工具-调试-统计总行数
android·ide·android studio
你的坚定9 小时前
SurfaceFlinger合成一帧的完整流程
android
爱笑鱼11 小时前
Android 系统启动机制(七):进入 SystemServer.main() 以后,system_server 还是一个空进程吗?
android·linux
好安静11 小时前
SurfaceFlinger 合成一帧的完整流程
android