返回和跳转

Kotlin 支持三个结构化的跳转表达式:

  • return 默认返回就近的封闭(enclosing)函数或者匿名函数
  • break 中断就近的封闭循环
  • continue 继续执行就近封闭循环的下一步操作

以上表达式可作为更大表达式的一部分:

  1. val s = person.name ?: return

以上表达式的类型Nothing

break & continue 标签

Kotlin 的每个表达式都可以用一个 label 来标记。标签的形式是标识符后面带一个 @ 符号,例如 abc@fooBar@ 都是合法的标签。如果要标记一个表达式,只需要在前面放一个 label:

  1. loop@ for (i in 1..100) {
  2. // ...
  3. }

现在,我们可以用一个 label 来限定 breakcontinue 的作用目标:

  1. loop@ for (i in 1..100) {
  2. for (j in 1..100) {
  3. if (...) break@loop
  4. }
  5. }

这里用标签限定过的 break 会跳转到标签所标记的循环语句执行处。continue 会继续执行循环的下一次迭代。

标签返回

借助 function literals、local functions 和 object expression,Kotlin 还支持函数嵌套。限定过的 return 允许我们直接从外围函数中返回。最重要的使用场景是从 lambda 表达式中返回。当我们写下下面的代码时:

  1. fun foo() {
  2. ints.forEach {
  3. if (it == 0) return // non-local return directly to the caller of foo()
  4. print(it)
  5. }
  6. }

return 表达式从就近的外围函数中返回 - foo。(注意:只有传入到内联函数的 lambda 表达式才支持非局部(non-local)返回。)。如果要从 lambda 表达式中返回,我们需要加标签并且限定 return

  1. fun foo() {
  2. ints.forEach lit@ {
  3. if (it == 0) return@lit // local return to the caller of the lambda, i.e. the forEach loop
  4. print(it)
  5. }
  6. }

现在,它只会从 lambda 表达式中返回。多数情况下,更便利的方式是使用隐式标签:标签与接收 lambda 表达式作为参数的函数名同名。

  1. fun foo() {
  2. ints.forEach {
  3. if (it == 0) return@forEach
  4. print(it)
  5. }
  6. }

除此之外,我们可以用一个匿名函数来代替 lambda。匿名函数中的 return 声明会从它自己当中返回。

  1. fun foo() {
  2. ints.forEach(fun(value: Int) {
  3. if (value == 0) return // local return to the caller of the annoymous fun, ie.e. the forEach loop
  4. print(value)
  5. }
  6. }

注意,上面三个例子当中 local return 的用法和常规循环中 continue 的作用类似。没有与 break 直接等价的用法,但是我们可以采用增加一个嵌套 lambda 并从中局部返回的做法来模拟实现:

  1. fun foo() {
  2. run loop@{
  3. listOf(1, 2, 3, 4, 5).forEach {
  4. if (it == 3) return@loop // non-local return from the lambda passed to run
  5. print(it)
  6. }
  7. }
  8. print("done with nested loop")
  9. }

当返回一个值时,parser 给予限定 return 更高的优先级。

  1. return@a 1

上面的代码意味着:“在标签@a处返回1”,而不是“返回一个标记过的表达式 (@a 1)”。


术语约定:

  1. enclosing function -> 封闭函数
  2. outer function -> 外围函数
  3. qualified -> 限定的