kotlin lambda的return

发布时间 2023-11-13 07:44:13作者: LCAC

一、lambda表达式是否可以使用reutnr

1、非内联函数的lambda表达式中使用return是不被允许

2、内联函数是允许使用return,它会从调用该lambda的函数中返回

fun lookForAlice(people: List<String>) { 
    people.forEach { // 这里forEach使用的是内联函数,从而forEach传入的lambda也使用内联函数
        if (it == "Alice") {
            println("found")
            return
        }
    }
    println("alice no found")
}

上面的这段代码翻译成java

   public static final void lookForAlice(@NotNull List people) {
      Iterable $this$forEach$iv = (Iterable)people;
      Iterator var3 = $this$forEach$iv.iterator();

      String it;
      do {
         if (!var3.hasNext()) {
            System.out.println("alice no found");
            return;
         }

         Object element$iv = var3.next();
         it = (String)element$iv;
         int var6 = false;
      } while(!Intrinsics.areEqual(it, "Alice"));

      System.out.println("found");
   }

如上可以看出,inline是会传递,并且内联函数在调用它代码的地方被替换成该函数的代码,那么return则显而易见是是从该lambda的父函数中返回

 

二、使用标签返回

1、可以使用标签的方式进行局部的返回(即跳出当前的lambda表达式),并非第一点提到的从调用它的函数返回

fun lookForAlice(people: List<String>) {
    people.forEach label@{ // 给lambda表达式添加标签
        if (it == "Alice") {
            println("found")
            return@label // 引用这个标签,将会返回到上述的label@的位置
        }
    }
    println("alice no found") // 这一行总是会被打印
}

如上所述,在lambda之前增加一个标签: label@ 这里的格式是:标签名+@ ,标签名可以自己取

在lambda的内部返回的格式是:return+@+标签名

2、也可以不用命名标签,会有一个默认的标签,比如1中的label@如果没有被添加,那么要从当前的lambda跳出,则可以用:return@forEach

fun lookForAlice(people: List<String>) {
    people.forEach { // 没有明确指定标签,则使用默认的标签:forEach
        if (it == "Alice") {
            println("found")
            return@forEach // 这里使用forEach这个默认的标签
        }
    }
    println("alice no found") // 这一行总是会被打印
}

3、一个lambda只能有一个标签,当指定了标签的名字之后,默认的标签则不会再生效。比如第1点中已经指明了名字为label的标签之后,下面就不能再使用return@forEach

4、带this的标签:当lambda是带接受者的时候,则可以使用带this的标签进行访问

    println(java.lang.StringBuilder().apply {
        listOf(1, 2, 3).apply {
            println(this) // 这里的this对应的对象是listOf()生成的这个list接受者
        }
    })

如上对应的this对应的是listOf, 那么如果要指明接收者是StringBuilder()的话,则需要使用标签

    println(java.lang.StringBuilder().apply sb@ {
        listOf(1, 2, 3).apply {
            this@sb.append(this.toString())
        }
    })

如上的this@sb指明this是StringBuilder,this.toString对应的this指的是listOf对应的对象

 

三、匿名函数:默认使用局部返回

第二点提到的使用标签返回,在lambda比较简短且return的出口比较少的时候还可以不算冗长,但是如果有多个return语句在lambda中的时候则会使整个lambda语句看着特别笨重

这里介绍的使用匿名函数的返回:默认使用局部返回

其实匿名函数也是函数的一种,函数内部的return本身只是跳出函数本身。从这点就比较容易理解匿名函数默认使用局部返回

fun lookForAlice(people: List<String>) {
    people.forEach (fun (person) {
        if (person == "Alice") return
        println("$person is not Alice")
    })
}

lookForAlice(listOf("aa", "Alice", "cc"))
/*
aa is not Alice
cc is not Alice
*/

如上的注释显示了调用lookForAlice打印的结果