为什么 lambda 不能使封闭函数 return?

Why a lambda cannot make the enclosing function return?

我对 Kotlin 很陌生。我在查看文档时遇到了这部分:

"a lambda cannot return from the enclosing function" (unless it's inlined).

所以,这行不通;

fun foo() {
    ordinaryFunction {
        return // ERROR: cannot make `foo` return here
    }
}

我想知道为什么会这样?

我唯一能想到的是它很危险,因为在 lambda 执行之后封闭函数可能会做一些额外的事情。但我不确定这就是原因,因为您可以通过使用限定的 returns 或使用 inline 关键字来克服这个问题。所以,这意味着它背后有一个技术原因(除了任何 usability/safety 原因),比如编译器无法确定 return 的位置,除非它被标记或内联。

任何帮助都会很棒!

问题出在non-local returns can't be done on the JVM。 如果你想从 lambda(本地 return)return,你可以添加标签 @ordinaryFunction:

fun foo() {
    ordinaryFunction {
        return@ordinaryFunction
    }
}

Docs 说:

If we need to return from a lambda expression, we have to label it and qualify the return. Oftentimes it is more convenient to use implicit labels: such a label has the same name as the function to which the lambda is passed. In our case it is @ordinaryFunction.

其他人可能可以更好地解释这一点,但在几乎任何编程语言中,当您调用一个函数时,都会在 堆栈 之上创建一个新条目。堆栈保留有关调用函数的参数的信息以及函数完成时您应该 return 的位置。

Kotlin 没有一项功能可以让您 return 在一个 return 中进行多个函数调用,因此您必须手动 return 从每个函数调用中进行。

当您内联一个函数时,通常在单独的子例程中执行的机器代码现在被复制粘贴到函数调用站点。这就是为什么来自内联函数的 return 实际上来自调用内联 lambda 的函数的 return。

there might be some extra stuff the enclosing function might be doing after the lambda execution.

问题是相反的:lambda 可以从封闭函数的作用域 "escape" 并在函数 return 之后执行。例如。考虑

fun foo() {
    Thread(Runnable { 
        Thread.sleep(1000)
        return
    })
}

或者只是

 fun foo() = // lambda

在任何一种情况下,从 foo 到 return 的 lambda 都没有意义,对吗?编译器不知道你的 ordinaryFunction 是否允许 lambda 逃逸 foo 的范围,除非它是内联的。

you can overcome this by using qualified returns

这并不是真正的克服,只是不是 return 封闭函数。