【问题标题】:Is non-local return in Scala new?Scala 中的非本地返回是新的吗?
【发布时间】:2011-08-02 16:59:48
【问题描述】:

一位同事刚刚向我展示了这个,我很惊讶它完全编译:

def toUpper(s: Option[String]): String = {
  s.getOrElse(return "default").toUpperCase
  //          ^^^^^^  // a return here in the closure??
}

这甚至可以工作:

println(toUpper(Some("text"))) // TEXT
println(toUpper(None))         // default

我认为不允许闭包内部的return。这从什么时候开始起作用了?这种非本地回报是否有警告?

【问题讨论】:

  • 非常混乱,因为Some("text").getOrElse(return "default").toUpperCaseNone.getOrElse(return "default").toUpperCase 都不能编译。
  • def foo(): String = Some("text").getOrElse(return "default").toUpperCase 编译正常; def foo(): String = (None: Option[String]).getOrElse(return "default").toUpperCase也是如此。
  • @Alexey 当然可以,但如果您删除 def foo():String = 部分,则不会。
  • @agilesteel 错误信息说需要有一个封闭的方法才能返回。
  • 我没有看到任何令人困惑的地方。 Scala 中的return 总是从封闭方法返回;如果您不在方法定义中,则不能使用return

标签: scala return control-flow


【解决方案1】:

语义相对简单:return 将抛出一个NonLocalReturnControl,该NonLocalReturnControl 被封闭方法toUpper 捕获。它看起来不像是最近的功能。自 2.0 版以来,Scala change-log 中没有提及 return

这是 Scala 语言规范第 6.20 节中的相关描述:

从嵌套的匿名函数返回是通过抛出来实现的 并捕获 scala.runtime.NonLocalReturnException。任何例外 返回点和封闭方法之间的捕获可能 见例外。一个关键的比较确保这些例外 仅被返回终止的方法实例捕获。

如果返回表达式本身是匿名函数的一部分,它 f 的封闭实例可能已经返回 在执行返回表达式之前。在这种情况下,抛出 scala.runtime.NonLocalReturnException 不会被捕获,并且会 向上传播调用堆栈。

这是一个 NonLocalReturnControl 转义的示例:

var g: () => Unit = _
def f() { g = () => return }
f() // set g
g() // scala.runtime.NonLocalReturnControl$mcI$sp

【讨论】:

  • 感谢您的信息!看起来它实际上是一个NonLocalReturnControl,它被抛出并被捕获。
  • @Kipton 怎么会出现“f 的封闭实例已经返回”的情况。你能举个例子吗?
【解决方案2】:

自古以来就被允许,或多或少。那里可能看起来很奇怪,但在很多地方情况正好相反。例如:

// excessive use of braces for the sake of making scopes clearer

def findFirst[A](l: List[A])(p: A => Boolean): Option[A] = {
    for (x <- l) {
        if (p(x)) return Some(x)
    }
    None
}

【讨论】:

    猜你喜欢
    • 2012-03-31
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 2012-12-18
    • 2014-11-24
    • 1970-01-01
    • 2012-11-20
    • 2013-01-14
    相关资源
    最近更新 更多