当前位置: 首页 > news >正文

Kotlin 2.1.0 入门教程(十一)for、while、return、break、continue

for 循环

for 循环会遍历任何提供迭代器的对象。

for (item in collection) print(item)for (int: Int in ints) {println(int)
}

for 循环会遍历任何提供迭代器的对象,这意味着该对象必须满足以下条件:

  • 具有一个成员函数或扩展函数 iterator(),该函数返回一个 Iterator<> 对象,而该对象:

    • 具有一个成员函数或扩展函数 next()

    • 具有一个成员函数或扩展函数 hasNext(),该函数返回一个 Boolean

  • 这三个函数都需要被标记为 operator

要遍历一个数字范围,可以使用范围表达式。

for (i in 1..3) {print(i)
}for (i in 6 downTo 0 step 2) {print(i)
}

对于范围或数组的 for 循环会被编译成基于索引的循环,而不会创建迭代器对象。

如果你想要通过索引遍历数组或列表,可以这样操作:

for (i in array.indices) {print(array[i])
}

或者,你可以使用 withIndex() 库函数。

for ((index, value) in array.withIndex()) {println("the element at $index is $value")
}

while 循环

whiledo-while 循环会在条件满足的情况下持续执行其主体。

它们之间的区别在于条件检查的时机:

  • while 循环会先检查条件,如果条件满足,则执行主体,然后返回检查条件。

  • do-while 循环会先执行主体,然后才检查条件。如果条件满足,则循环重复执行。因此,do-while 的主体至少会执行一次,无论条件是否满足。

while (x > 0) {x--
}do {val y = retrieveData()
} while (y != null) // y 在这里是可以访问的。

在循环中,Kotlin 支持传统的 breakcontinue 操作符。

返回和跳转

Kotlin 提供了三种结构化跳转表达式:

  • return:默认情况下,return 会从最近的封闭函数或匿名函数中返回。

  • break:会终止最近的封闭循环。

  • continue:会跳过当前循环的当前迭代,继续执行下一次迭代。

fun example() {for (i in 1..10) {if (i == 5) {return // 从函数 example 中返回。}println(i)}
}
fun example() {for (i in 1..10) {if (i == 5) {break // 终止最近的循环。}println(i)}
}
fun example() {for (i in 1..10) {if (i == 5) {continue // 跳过当前迭代,继续下一次迭代。}println(i)}
}

return 的作用范围:

  • 在匿名函数(如 fun 声明的函数)中,return 会从该函数返回。

  • Lambda 表达式中,return 会从最近的封闭函数返回,而不是从 Lambda 表达式返回。如果需要从 Lambda 表达式返回,可以使用标签。

breakcontinue 的作用范围:

  • breakcontinue 只能用于循环结构(如 forwhiledo-while)。

  • 如果需要从嵌套循环中跳出,可以使用标签。

如果需要从嵌套循环中跳出,或者从 Lambda 表达式中返回,可以使用标签。例如:

loop@ for (i in 1..3) {for (j in 1..3) {if (i == 2 && j == 2) {break@loop // 从带有标签的外层循环中跳出。}println("i = $i, j = $j")}
}

所有这些表达式都可以作为更大表达式的一部分使用:

val s = person.name ?: return

这些表达式的类型是 Nothing 类型。

Nothing 类型是 Kotlin 中的一个特殊类型,表示《无值》。它是一个不可实例化的类型,表示代码不会返回任何值,通常用于表示程序的退出点(如 returnthrow 等)。

在上面的例子中:

  • person.name 是一个可能为 null 的表达式。

  • ?:Kotlin 的空合并运算符(Elvis 运算符),用于提供一个默认值,当左侧表达式为 null 时,返回右侧的值。

  • 如果 person.name 不为 null,则 s 将被赋值为 person.name

  • 如果 person.namenull,则执行 return,表示从当前函数返回。

  • 由于 return 是一个跳转表达式,它不会返回任何值,因此它的类型是 Nothing。这意味着 val s = person.name ?: return 这行代码在 person.namenull 时,会直接从函数返回,而不会继续执行后续代码。

带标签的 breakcontinue

Kotlin 中,任何表达式都可以被标记上一个标签。

标签的格式是一个标识符后跟一个 @ 符号,例如 abc@fooBar@

要给一个表达式加上标签,只需在它前面添加一个标签即可。

fun main() {/*i = 1, j = 11i = 1, j = 12i = 1, j = 13i = 1, j = 14i = 1, j = 15i = 2, j = 11i = 2, j = 12*/loop@ for (i in 1..5) {for (j in 11..15) {if (i == 2 && j == 13) {break@loop}println("i = $i, j = $j")}}
}
fun main() {/*i = 1, j = 11i = 1, j = 12i = 1, j = 13i = 1, j = 14i = 1, j = 15i = 2, j = 11i = 2, j = 12i = 3, j = 11i = 3, j = 12i = 3, j = 13i = 3, j = 14i = 3, j = 15i = 4, j = 11i = 4, j = 12i = 4, j = 13i = 4, j = 14i = 4, j = 15i = 5, j = 11i = 5, j = 12i = 5, j = 13i = 5, j = 14i = 5, j = 15*/loop@ for (i in 1..5) {for (j in 11..15) {if (i == 2 && j == 13) {continue@loop}println("i = $i, j = $j")}}
}

在某些情况下,你可以在没有显式定义标签的情况下,非本地地(non-locally)使用 breakcontinue。这种非本地的用法在嵌套的内联函数中使用的 Lambda 表达式中是有效的。

breakcontinue 通常只能在它们所在的循环中使用。然而,在某些特定的上下文中,它们可以跨越多个作用域进行跳转,这种行为被称为《非本地跳转》。

当一个 Lambda 表达式被传递给一个内联函数(inline 函数)时,breakcontinue 可以在 Lambda 表达式中使用,而它们的作用范围会扩展到内联函数的调用点。这意味着你可以从 Lambda 表达式中跳转到外层的循环。

inline fun processList(list: List<Int>, action: (Int) -> Unit) {for (item in list) {action(item)}
}fun main() {val numbers = listOf(1, 2, 3, 4, 5)processList(numbers) { number ->if (number == 3) {break // 非本地 break,跳出 processList 的循环。}println(number)}
}

这种非本地跳转允许你从 Lambda 表达式中直接跳出外层的循环。

只有在内联函数中使用的 Lambda 表达式才支持非本地跳转。这是因为内联函数会将 Lambda 表达式直接插入到调用点,从而允许跳转到外层的作用域。

带标签的 return

函数可以通过函数字面量、局部函数和对象表达式进行嵌套。带标签的 return 允许你从外层函数返回。

最重要的用例是从 Lambda 表达式中返回。要从 Lambda 表达式返回,需要给 Lambda 表达式加上标签,并使用带标签的 return

fun main() {fun foo() {listOf(1, 2, 3, 4, 5).forEach lit@ {if (it == 3) return@litprint(it)}}foo() // 1245
}

现在,它只从 Lambda 表达式返回。

通常,使用隐式标签会更加方便,因为这种标签的名称与 Lambda 表达式所传递到的函数名称相同。

fun main() {fun foo() {listOf(1, 2, 3, 4, 5).forEach {if (it == 3) return@forEachprint(it)}}foo() // 1245
}

或者,你可以将 Lambda 表达式替换为匿名函数。在匿名函数中,return 语句将从匿名函数本身返回。

fun main() {fun foo() {listOf(1, 2, 3, 4, 5).forEach(fun (v: Int) {if (v == 3) returnprint(v)})}foo() // 1245
}

请注意,在前面的三个例子中,本地返回的使用与在普通循环中使用 continue 是类似的。

虽然没有直接等价于 break 的功能,但可以通过添加一个嵌套的 Lambda 表达式,并从其中非本地返回来模拟 break 的行为。

fun main() {// 12run loop@ {listOf(1, 2, 3, 4, 5).forEach {if (it == 3) return@loopprint(it)}}
}
fun main() {// 12run loop@ {listOf(1, 2, 3, 4, 5).forEach(fun (v: Int) {if (v == 3) return@loopprint(v)})}
}

当返回一个值时,解析器会优先考虑带标签的返回:

return@a 1

它是:在标签 @a 处返回值 1。而不是:返回一个带标签的表达式 @a 1

在某些情况下,你可以在不使用标签的情况下从 Lambda 表达式返回。这种非本地返回位于 Lambda 表达式中,但会退出封闭的内联函数。


http://www.mrgr.cn/news/89989.html

相关文章:

  • Visual Studio Code (VSCode) 的基本设置指南,帮助你优化开发环境
  • 水下 SLAM 定位模组的设计与实现
  • 基于微信小程序的医院预约挂号系统的设计与实现
  • VMware 虚拟机中 Ubuntu 20 网络不通问题解决总结
  • Spring Cloud 03 - 配置中心
  • WebSocket推送数据快,条数多导致前端卡顿问题解决
  • 10vue3实战-----实现登录的基本功能
  • Python截图轻量化工具
  • 激活函数篇 03 —— ReLU、LeakyReLU、RandomizedLeakkyReLU、PReLU、ELU
  • BiGRU双向门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据)
  • 2025.2.9机器学习笔记:PINN文献阅读
  • 机器学习基本概念(附代码)
  • windows通过网络向Ubuntu发送文件/目录
  • python循环
  • redis专栏解读
  • 外部中断实验 #STM32F407
  • 半导体制造工艺讲解
  • CNN卷积神经网络多变量多步预测,光伏功率预测(Matlab完整源码和数据)
  • Redis基础--常用数据结构的命令及底层编码
  • C++ Attribute 属性说明符
  • 人工智能图像分割之Mask2former源码解读
  • C语言练习题
  • burpsuite抓取html登陆和上传数据包
  • open3d将numpy数组可视化
  • 本地部署DeepSeek + Ragflow
  • python - 封装moondream(备份)