6

たとえば、次のようなメソッドがある場合

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

(もちろん、これにはライブラリ関数があります。これは単なる例です)。foreach内部関数returnが s の場合、実行はどのようにエスケープしますか?

または

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

が発行されprocessたときに、実行はどのように実行を回避しますか?return ""

4

1 に答える 1

3

foo例は、

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

です。あなたは実行されていないことを示唆しているので、私は前者を想定してprocessいます。これは、引数を渡すときに常に機能する方法です。最初に引数の作成作業を行い、次にメソッドを呼び出します。に遭遇したのでreturn、それは簡単です:return引数* の作成中に適切な from バイトコードを呼び出すだけで、メソッドを呼び出すことはありません。したがって、それ単なるローカルリターンです。

このfind例はもう少し複雑です。foo非ローカルな戻り値を必要とする aによって動機付けられた、非常に単純な例を試してみましょう。

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にしか実行されないことにも注意してください。この場合、最初に実際の文字列を埋めるために を使用しようとするため、何も出力しませんが、制御を に戻す例外に遭遇します。(したがって、 から空の文字列が返されますが、何も出力されません。)sfoofoo

*実際、バイトコードではメソッドの最後にジャンプする傾向があり、そこに load/return があります。概念的には関係ありませんが。

于 2013-07-17T21:44:26.170 に答える