【问题标题】:Why a lambda cannot make the enclosing function return?为什么 lambda 不能使封闭函数返回?
【发布时间】:2019-02-19 13:23:51
【问题描述】:

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

“一个 lambda 不能从封闭函数返回”(除非它是内联的)。

所以,这行不通;

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

我想知道为什么它会这样工作?

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

任何帮助都会很棒!

【问题讨论】:

    标签: function lambda kotlin anonymous-function


    【解决方案1】:

    问题在于non-local 返回can't be done on the JVM。 如果要从 lambda(本地返回)返回,可以添加标签 @ordinaryFunction

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

    Docs说:

    如果我们需要从 lambda 表达式返回,我们必须标记它并限定 return。通常使用隐式标签更方便:这样的标签与传递 lambda 的函数具有相同的名称。在我们的例子中是@ordinaryFunction

    【讨论】:

    • 这与“如何”做无关。它更多的是关于引擎盖下的动态,比如“为什么”编译器不允许这样做。毕竟都是“函数类型”对吧。
    【解决方案2】:

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

    Kotlin 没有让您从多个函数调用一次返回的功能,因此您必须手动从每个函数调用返回。

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

    【讨论】:

    • 我明白你的意思,但它怎么能与匿名函数一起工作,但不能与 lambdas 一起工作? Lambda 还创建了一个函数类型。
    • 在匿名函数中,return 从匿名函数返回,而不是从封闭函数返回。 (规则是return 总是从最近的fun 返回,除非你像return@something 那样限定它。)
    【解决方案3】:

    在 lambda 执行之后,封闭函数可能会做一些额外的事情。

    问题是反过来的:lambda 可以从封闭函数的作用域“逃逸”,并在函数返回后执行。例如。考虑

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

    或者只是

     fun foo() = // lambda
    

    无论哪种情况,lambda 从foo 返回都没有意义,是吗?并且编译器不知道您的 ordinaryFunction 是否让 lambda 转义 foo 的范围,除非它是内联的。

    你可以通过使用合格的回报来克服这个问题

    这并没有真正克服,只是没有从封闭函数返回。

    【讨论】:

      猜你喜欢
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-11
      • 2023-03-27
      • 2012-03-08
      • 1970-01-01
      相关资源
      最近更新 更多