要するに:
例 A は理論的には高速ですが、実際には違いを測定することはできません。
長い答え:
すでにお分かりのとおり
for {xs <- xxs; x <- xs} f(x)
に翻訳されます
xxs.foreach(xs => xs.foreach(x => f(x)))
これは §6.19 SLS で説明されています。
for ループ
for ( p <- e; p' <- e' ... ) e''
ここで、... はジェネレーター、定義、またはガードの (場合によっては空の) シーケンスであり、次のように変換されます。
e .foreach { case p => for ( p' <- e' ... ) e'' }
関数リテラルを記述すると、関数を呼び出す必要があるたびに新しいインスタンスが取得されます (§6.23 SLS)。この意味は
xs.foreach(x => f(x))
と同等です
xs.foreach(new scala.Function1 { def apply(x: T) = f(x)})
ローカル関数型を導入する場合
val g = f _; xxs.foreach(xs => xs.foreach(x => g(x)))
関数リテラルを にまだ渡しているため、最適化を導入していませんforeach
。実際には、内部foreach
が次のように変換されるため、コードは遅くなります。
xs.foreach(new scala.Function1 { def apply(x: T) = g.apply(x) })
apply
のメソッドへの追加の呼び出しがg
発生する場所。ただし、書き込み時に最適化できます
val g = f _; xxs.foreach(xs => xs.foreach(g))
内側のforeach
now が変換されるため
xs.foreach(g())
これは、関数g
自体が に渡されることを意味しforeach
ます。
これは、 for 内包表記の本体が実行されるたびに無名関数を作成する必要がないため、理論的には B の方が高速であることを意味します。ただし、上記の最適化 (関数が に直接渡されるforeach
) は内包表記には適用されません。仕様にあるように、変換には関数リテラルの作成が含まれているため、不要な関数オブジェクトが常に作成されるためです (ここでは、コンパイラーもそれを最適化できますが、内包表記の最適化は難しく、2.11 ではまだ行われていないため、そうではありません)。全体として、A はより効率的ですが、for 内包表記なしで記述された場合 (そして最も内側の関数に対して関数リテラルが作成されない場合)、B はより効率的であることを意味します。
それにもかかわらず、これらのルールはすべて理論的にしか適用できません。実際には、最適化を実行できる scalac のバックエンドと JVM 自体があり、CPU によって実行される最適化は言うまでもありません。さらに、あなたの例には、すべての反復で実行される syscall が含まれています。これはおそらく、ここで最も高価な操作であり、他のすべてよりも重要です。