【问题标题】:How does Scala implement return from within an expression?Scala 如何实现从表达式中返回?
【发布时间】:2013-07-17 15:31:32
【问题描述】:

例如,如果我们有一个类似的方法

def find[A](xs: Seq[A], p: A => Boolean): Option[A] = {
  xs.foreach(x => if (p(x)) return Some(x));
  None;
}

(当然有一个库函数,这只是一个例子)。内部函数returns时,执行如何逃逸foreach

或者在

def foo(x: AnyRef): String =
  process(x match {
    case (s: String) => s;
    case _           => return "";
  })

在发出return "" 时,执行如何避免运行process

【问题讨论】:

标签: scala return implementation anonymous-function


【解决方案1】:

foo 示例取决于哪个

def process(s: String): String
def process(s: => String): String

确实如此。我假设前者,因为你建议 process 没有运行。这正是传递参数时始终工作的方式——你首先进行参数创建工作,然后调用方法。由于您遇到return,这很容易:您只需在创建参数* 时从字节码中调用适当的return,并且永远不要继续调用该方法。所以它只是一个本地返回。

find 的例子有点复杂。让我们尝试一个由foo 驱动的最简单的示例,该示例需要非本地返回:

class Nonlocal {
  def pr(s: => String) = { println(s); "Printed" }

  def foo(x: AnyRef): String = pr(x match {
    case (s: String) => s;
    case _           => return "";
  })
}

foo 的正文相当于

import scala.runtime.NonLocalReturnControl
val temp = new AnyRef
try {
  pr(x match {
    case s: String => s
    case _         => throw new NonLocalReturnControl(temp, "")
  })
}
catch {
  case nlrc: NonLocalReturnControl[_] if (nlrc.key eq temp) =>
    nlrc.value.asInstanceOf[String]
}

要注意的关键是创建了一个哨兵对象,以便这些东西可以任意嵌套而不会相互破坏,并且NonLocalReturnControl 会返回正确的值。不出所料,与仅仅返回 Int 相比,这并不便宜。但是由于它创建了一个没有堆栈跟踪的异常(安全,因为它无法逃脱:catch 块保证会捕获它),它并不是 那个 坏 - 差不多一样坏调用一个三角函数或对一个包含几十个条目的数组求和。

另请注意,pr 仅在异常得到它之前部分执行。在这种情况下,它不会打印任何内容,因为它所做的第一件事是尝试使用s 来填充实际的字符串,但随后它会遇到异常,将控制权放回foo。 (所以你从foo 得到一个空字符串,但你不打印任何东西。)

* 实际上,在字节码中,它倾向于跳转到方法的末尾,并在那里加载/返回。不过,在概念上无关紧要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多