kotlin lambda的return
一、lambda表达式是否可以使用return
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打印的结果