[英]Strange (?) for comprehension evaluation in Scala
現在,我花了一段時間才弄清楚為什么我的遞歸以某種方式成功地炸掉堆棧。 這就是導致這個問題的部分:
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
結尾, if false
永遠不會被使用?
我學到了什么,而不是{ println ... }
你有一個遞歸調用(和遞歸防護,而不是if false
),會發生什么。 <
為什么?!
我打算走出去,說接受的答案可以說更多。
這是一個解析器錯誤。
防護裝置可以立即跟隨發電機,但是否則需要semi
(實際或推斷)。
在下面, res4
的行res4
應該編譯。
scala> for (i <- (1 to 5).toList ; j = 2 * i if j > 4) yield j
res4: List[Int] = List(6, 8, 10)
scala> for (i <- (1 to 5).toList ; j = 2 * i ; if j > 4) yield j
res5: List[Int] = List(6, 8, 10)
會發生什么是j的val def與i生成器合並以生成一對新的生成器對(i,j)
。 然后警衛看起來就像跟隨(合成)發電機一樣。
但語法仍然是錯誤的。 語法是我們的朋友! 在類型系統之前很久就是我們的BFF。
在res5
的線路上,很明顯守衛沒有防守val def。
更新:
實施錯誤被降級(或升級,取決於您的觀點)到規范錯誤 。
檢查這種用法,如果控制前面的valdef,就像在Perl中一樣,后衛看起來像尾隨,屬於你最喜歡的樣式檢查器的范圍。
如果您像這樣構建循環,它將解決您的問題:
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語句視為一種過濾器; 本教程有一些很好的例子。
考慮它的一種方法是強制執行for循環,當你到達if語句時,如果該語句的計算結果為false,則繼續循環的下一次迭代。
當我遇到這樣的問題時,我試圖了解反匯編代碼的樣子(例如,將.class文件提供給JD-GUI)。
這個for-comprehension反匯編代碼的開頭看起來像這樣:
((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
方法首先執行println
nomatter,然后將Unit
分配給參數j
最后返回一個二元組(i,j)到另一個管道它進入進一步的過濾/映射操作(省略)。 因此,基本上if false
條件沒有任何影響,並且基本上被編譯器刪除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.