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);
}
相关推荐
CANI_PLUS8 小时前
ESP32将DHT11温湿度传感器采集的数据上传到XAMPP的MySQL数据库
android·数据库·mysql
来来走走9 小时前
Flutter SharedPreferences存储数据基本使用
android·flutter
安卓开发者10 小时前
Android模块化架构深度解析:从设计到实践
android·架构
雨白10 小时前
HTTP协议详解(二):深入理解Header与Body
android·http
阿豪元代码11 小时前
深入理解 SurfaceFlinger —— 如何调试 SurfaceFlinger
android
阿豪元代码11 小时前
深入理解 SurfaceFlinger —— 概述
android
CV资深专家12 小时前
Launcher3启动
android
stevenzqzq13 小时前
glide缓存策略和缓存命中
android·缓存·glide
雅雅姐13 小时前
Android 16 的用户和用户组定义
android
没有了遇见13 小时前
Android ConstraintLayout 之ConstraintSet
android