问题:非本地return
我们先通过一个简单的例子来理解非本地return的问题:
fun doSomething() {
println("Before lambda")
doSomethingElse {
println("Inside lambda")
return // This is non-local return
}
println("After lambda")
}
inline fun doSomethingElse(lambda: () -> Unit) {
println("Do something else")
lambda()
}
非本地return
在上面的代码中,return 语句被称为非本地返回,因为它对于调用它的函数来说不是本地的。这意味着这个return 语句是doSomething() 函数的本地语句,而不是调用它的lambda 函数。因此,它终止了当前函数以及最外层的函数。
本地return
如果你只是想从 lambda 返回,你会说return@doSomethingElse。这称为local return,它是指定它的函数的本地。
问题
现在这里的问题是编译器跳过了非本地return 语句之后的行。 doSomething() 的反编译字节码如下所示:
public static final void doSomething() {
System.out.println("Before lambda");
System.out.println("Doing something else");
System.out.println("Inside lambda");
}
请注意,没有为行println("After lambda") 生成语句。这是因为我们在 lambda 中有非本地的return,编译器认为return 语句之后的代码没有意义。
解决方案:crossinline关键字
crossinline
在这种情况(如上面提到的问题)中,解决方案是禁止lambda 内的非本地return。为此,我们将lambda 标记为crossinline:
inline fun doSomethingElse(crossinline lambda: () -> Unit) {
println("Doing something else")
lambda()
}
不允许使用非本地return
当您使用 crossinline 关键字时,您是在告诉编译器,“如果我不小心在嵌套函数或本地对象中使用了非本地 return,请给我一个错误。”:
fun doSomething() {
println("Before lambda")
doSomethingElse {
println("Inside lambda")
return // Error: non-local return
return@doSomethingElse // OK: local return
}
println("After lambda")
}
现在编译器按预期生成字节码:
public static final void doSomething() {
System.out.println("Before lambda");
System.out.println("Doing something else");
System.out.println("Inside lambda");
System.out.println("After lambda");
}
就是这样!希望我能让它更容易理解。