ここでは何が起こりますか。あなたはScalaのREPLでイテレータを定義すると、そのイテレータに関するいくつかの情報は、それが特に空かないのかどうか、印刷されています
この情報は、次のように定義されて
Iterator
の
toString
方法によって返され
scala> Iterator.continually(List(1)).flatten
res1: Iterator[Int] = non-empty iterator
:
override def toString = (if (hasNext) "non-empty" else "empty")+" iterator"
基本的には、hasNext
が新しく作成されたイテレータで呼び出されます。今度はhasNext
は、あなたのケース(scala.collection.TraversableOnce.FlattenOps#flatten
)に何をするか見てみましょう:
class FlattenOps[A](travs: TraversableOnce[TraversableOnce[A]]) {
def flatten: Iterator[A] = new AbstractIterator[A] {
val its = travs.toIterator
private var it: Iterator[A] = Iterator.empty
def hasNext: Boolean = it.hasNext || its.hasNext && { it = its.next().toIterator; hasNext }
def next(): A = if (hasNext) it.next() else Iterator.empty.next()
}
}
なるほど! hasNext
は、反復的に反復子を走査して、空でない要素が1つも見つからないようにします。あなたの場合、空の要素の無限反復子があるので、決して起こることはありません。ですから、あなたはREPLによって引き起こされる無限ループを持っています。テール再帰が使用され、スカラではwhileループに移行されるので、StackOverflow
は得られません。
いいです。 '(1〜10).iterator span(_ <5)'のように 'toString'をオーバーライドする必要があります。 –
@ som-snytt、 'toString'を指摘してくれてありがとう、何らかの理由で、REPLがかなりの値を印刷するために何か他のものを使っていると想像しました。おそらく、私は[アンモナイト](http://www.lihaoyi.com/Ammonite/#Ammonite-REPL)を念頭に置いていましたが、これは標準タイプに 'toString'を使用していません。とにかく、すべての部分がその場にあります。 – Aivean
違う方法で 'toString'をオーバーライドしたとしても、イテレータを何かのために使用しようとしたときに、同じ無限ループを繰り返します... OPが作成したものは、無限ループが起こるのを待っています。 「平らな」とはどういう意味ですか? –