次のコードは、クラスのコンストラクター内で1回呼び出されるメソッド自体から1回呼び出されます。スペックUnitTestの一部として実行されると、テストがスタックし、より多くのメモリを消費するjavawプロセスがすぐに生成されます。
private def placeMines( excludes: List[( Int, Int )] ) {
def rndstream: Stream[( Int, Int )] = {
def s: Stream[( Int, Int )] =
( Random.nextInt( ysize ), Random.nextInt( xsize ) ) #:: s
s
}
def posPermitted( pos: ( Int, Int ) ): Boolean = {
!excludes.contains( pos ) &&
fieldEmpty( pos._1, pos._2 )
}
val positions = rndstream.filter( posPermitted )
positions.take( minecount ).foreach( x => grid( x._1 )( x._2 ) = MineField() )
}
何が起こっているのかを知るために、最後の行を副作用(グリッドは2次元配列)でコメントアウトし、フィルター述語をx=>falseやx=>trueなどの別の述語に置き換えました。興味深いことに、それは真の場合に終了しますが、偽で永遠に実行され続けます。いくつかのprintlnを挿入すると、Javaプロセスを終了する前に、述語が数十万回呼び出されることが示されています。
次のコードで状況を再現しようとしました。
import scala.util.Random
import org.specs.SpecificationWithJUnit
class foobar extends SpecificationWithJUnit {
val x = 0xDead
val y = 0xBeef
bar(x, y)
private def bar(x: Int, y: Int) = foo(x)
private def foo(x: Int) = {
def s: Stream[( Int, Int )] = {
def p: Stream[( Int, Int )] =
( Random.nextInt( x ), Random.nextInt( y ) ) #:: p
p
}
val fiveodd = s.filter( x => x._1 % 2 == 1 )
println( fiveodd.take( 5 ).toList )
}
}
ただし、そのコードは問題なく実行されます。
「scalastreamfilterendless」、「scala streamfilterforcesvaluation」および「scalastreamfilterdoes not end」の検索では、原則として私のコードと同じように見えるストリームの使用法を示すチュートリアルのみが表示されました。