Kotlin return@label到底怎么用

在 Kotlin 中,经常对 return@xxx 感到迷惑:

  • return@forEach 是什么意思?
  • 为什么不能直接 return
  • @label 是什么东西?是 goto 吗? 本文将结合示例 + 源码+ java代码理解 Kotlin 控制流标签用法。

开头结论

return@label 的本质是:

从当前标签所标记的 lambda 或表达式块中跳出,并继续执行其后的代码。

结合场景分析

forEach 中正确跳过当前项

java 复制代码
listOf(1, 2, 3, 4).forEach {
    if (it == 2) return@forEach
    println(it)
}

Kotlin源码:

java 复制代码
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

说明:

  • action 是一个 (T) -> Unit 类型的 lambda
  • return@forEach 实际上是指:从当前 action lambda 中返回,跳过后续语句,继续下一轮调用,起到了continue的作用

转换为java代码验证:

java 复制代码
Integer[] $this$forEach$iv = new Integer[]{1, 2, 3, 4};
Iterable $this$forEach$iv = (Iterable)CollectionsKt.listOf($this$forEach$iv);
int $i$f$forEach = 0;

for(Object element$iv : $this$forEach$iv) {
   int it = ((Number)element$iv).intValue();
   int var6 = 0;
   if (it != 2) {
      System.out.println(it);
   }
}

等价于continue,只跳过了it == 2

java 复制代码
listOf(1, 2, 3, 4).forEach {
    if (it == 2) return
    println(it)
}

那么改为return呢

java 复制代码
Integer[] $this$forEach$iv = new Integer[]{1, 2, 3, 4};
Iterable $this$forEach$iv = (Iterable)CollectionsKt.listOf($this$forEach$iv);
int $i$f$forEach = 0;

for(Object element$iv : $this$forEach$iv) {
 int it = ((Number)element$iv).intValue();
 int var6 = 0;
 if (it == 2) {
    return;
 }

 System.out.println(it);
}

整个方法结束运行

多层 forEach 中跳出一层循环

java 复制代码
fun test() {
    listOf(1, 2).forEach outer@ { i ->
        listOf("A", "B").forEach { j ->
            if (j == "B") return@outer  // 跳出当前 i 的整轮内层循环,进入下一个 i
            println("i = $i, j = $j")
        }
    }
}

说明:结束外层 forEach outer@ 当前这一次 lambda 执行,跳出它对应的代码块,进入下一次迭代。

转换为java代码验证:

java 复制代码
for(Object element$iv : $this$forEach$iv) {
   int i = ((Number)element$iv).intValue();
   int var6 = 0;
   String[] $this$forEach$iv = new String[]{"A", "B"};
   Iterable $this$forEach$iv = (Iterable)CollectionsKt.listOf($this$forEach$iv);
   int $i$f$forEach = 0;

   for(Object element$iv : $this$forEach$iv) {
      String j = (String)element$iv;
      int var12 = 0;
      if (Intrinsics.areEqual(j, "B")) {
         break;
      }

      String var13 = "i = " + i + ", j = " + j;
      System.out.println(var13);
   }
}

多层 lambda 中跳出外层块

java 复制代码
fun test() {
    run outer@ {
        listOf(1, 2, 3).forEach { i ->
            listOf("A", "B").forEach { j ->
                if (i == 2 && j == "B") return@outer  // 跳出 run@outer
                println("i = $i, j = $j")
            }
        }
    }
    println("done")
}

说明:return@outer 会跳出整个 run outer@ { ... } 的 lambda 表达式块

转换为java代码验证:

java 复制代码
TestReturn $this$test_u24lambda_u242 = this;
int var3 = 0;
Integer[] $this$forEach$iv = new Integer[]{1, 2, 3};
Iterable $this$forEach$iv = (Iterable)CollectionsKt.listOf($this$forEach$iv);
int $i$f$forEach = 0;

label24:
for(Object element$iv : $this$forEach$iv) {
   int i = ((Number)element$iv).intValue();
   int var9 = 0;
   String[] $this$forEach$iv = new String[]{"A", "B"};
   Iterable $this$forEach$iv = (Iterable)CollectionsKt.listOf($this$forEach$iv);
   int $i$f$forEach = 0;

   for(Object element$iv : $this$forEach$iv) {
      String j = (String)element$iv;
      int var15 = 0;
      if (i == 2 && Intrinsics.areEqual(j, "B")) {
         break label24;
      }

      String var16 = "i = " + i + ", j = " + j;
      System.out.println(var16);
   }
}

String var1 = "done";
System.out.println(var1);

等价于java的break label,跳出外层循环。

示例输出:

java 复制代码
i = 1, j = A
i = 1, j = B
i = 2, j = A
done

with, run, let 等内联表达式中提前结束

java 复制代码
fun test() {
    val result = run label@ {
        val x = getSomeValue()
        if (x == null) return@label "default" // 提前退出表达式块
        println("x is not null")
        "value is $x"
    }
    println(result)
}

说明:return@label 退出 run 表达式并返回值

转换为java代码验证:

java 复制代码
public final void test() {
   TestReturn $this$test_u24lambda_u240 = this;
   int var4 = 0;
   String x = $this$test_u24lambda_u240.getSomeValue();
   String var10000;
   if (x == null) {
      var10000 = "default";
   } else {
      String var6 = "x is not null";
      System.out.println(var6);
      var10000 = "value is " + x;
   }

   String result = var10000;
   System.out.println(result);
}
相关推荐
xchenhao17 分钟前
基于 Flutter 的开源文本 TTS 朗读器(支持 Windows/macOS/Android)
android·windows·flutter·macos·openai·tts·朗读器
coder_pig1 小时前
跟🤡杰哥一起学Flutter (三十五、玩转Flutter滑动机制📱)
android·flutter·harmonyos
消失的旧时光-19432 小时前
OkHttp SSE 完整总结(最终版)
android·okhttp·okhttp sse
ansondroider3 小时前
OpenCV 4.10.0 移植 - Android
android·人工智能·opencv
itgather7 小时前
安卓设备信息查看器 - 源码编译
android
whysqwhw7 小时前
OkHttp之buildSrc模块分析
android
hsx6667 小时前
从源码角度理解Android事件的传递流程
android
刺客xs8 小时前
MYSQL数据库----DCL语句
android·数据库·mysql
iReaShare9 小时前
如何将数据从一部手机传输到另一部手机?
android