4

さて、再帰がどういうわけかスタックを吹き飛ばしてしまう理由を理解するのにしばらく時間がかかりました。これが、この問題の原因となっている部分です。

scala> for {
     |   i <- List(1, 2, 3)
     |   j = { println("why am I evaluated?"); 10 } if false
     | } yield (i, j)
why am I evaluated?
why am I evaluated?
why am I evaluated?
res0: List[(Int, Int)] = List()

これは、非常識ではありませんか?j = ...それがで終わるかどうかを評価しif falseて、決して使用されないのはなぜですか?

{ println ... }代わりに再帰呼び出し (および の代わりに再帰ガード) を使用するとどうなるかif false、私は学びました。:<

どうして?!

4

3 に答える 3

3

ループを次のように構成すると、問題が解決します。

scala> for {
     |   i <- List(1, 2, 3)
     |   if false
     |   j = { println("why am I evaluated?"); 10 }
     | } yield (i, j)
res0: List[(Int, Int)] = List()

for ループ内の Scala 構文は、if ステートメントを一種のフィルターとして扱います。このチュートリアルには、いくつかの良い例があります。

これを考える 1 つの方法は、for ループを命令的に通り抜けることです。if ステートメントに到達したときに、そのステートメントが false と評価された場合は、ループの次の繰り返しに進みます。

于 2013-10-25T22:09:07.113 に答える
2

そのような質問があるときは、逆アセンブルされたコードがどのように見えるかを確認しようとします (たとえば、.class ファイルを JD-GUI にフィードします)。

この理解のために逆アセンブルされたコードの冒頭は、次のようになります。

((TraversableLike)List..MODULE$.apply(Predef..MODULE$.wrapIntArray(new int[] { 1, 2, 3 })).map(new AbstractFunction1() { public static final long serialVersionUID = 0L;

      public final Tuple2<Object, BoxedUnit> apply(int i) { Predef..MODULE$.println("why am I evaluated?"); BoxedUnit j = BoxedUnit.UNIT;

        return new Tuple2(BoxesRunTime.boxToInteger(i), 
          j);
      }
    }...//continues

ここで、iパラメータの int の配列が、AbstractFunction1()そのapplyメソッドが最初にprintlnnomatter what を実行し、次にUnitパラメータに割り当てて、j最終的に two(i,j) のタプルを返し、それをさらなるフィルタ/マップ操作にさらにパイプすることにマップすることがわかります(省略)。したがって、基本的にif false条件は効果がなく、基本的にコンパイラによって削除されます。

于 2013-10-25T22:24:52.637 に答える