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);
}
相关推荐
晓梦林8 小时前
cp520靶场学习笔记
android·笔记·学习
有味道的男人10 小时前
Open Claw对接1688平台
android·rxjava
_李小白11 小时前
【android opencv学习笔记】Day 17: 目标追踪(MeanShift)
android·opencv·学习
用户860225046747212 小时前
AI 分析头部APP系统优化框架
android
用户860225046747212 小时前
AI分析头部APP优化框架
android
2501_9160074715 小时前
iOS开发中抓取HTTPS请求的完整解决方法与步骤详解
android·网络协议·ios·小程序·https·uni-app·iphone
lvronglee17 小时前
【数字图传第四步】Android App查看图传视频
android·音视频
90后的晨仔18 小时前
Android 程序入口与核心组件详解
android
90后的晨仔18 小时前
Kotlin 简介与开发环境搭建
android
BU摆烂会噶18 小时前
【LangGraph】House_Agent 实战(四):预定流程 —— 中断与人工干预
android·人工智能·python·langchain