Iterator.duplicateの動き
直前のエントリで気になったのでIterator.duplicateの動きを調べてみた。
val it = Iterator.continually... val (it1, it2) = it.duplicate println(it.foldLeft(0)((c, _) => c+1)) println(it1.foldLeft(0)((c, _) => c+1)) println(it2.foldLeft(0)((c, _) => c+1))
これだと、最初の一回目は行数が出てくるが、二回目、三回目では出てこない。duplicateとはいいつつ、元のIteratorを参照しているのだろうか。
そこでこうしてみる。
val it = Iterator.continually... val (it1, it2) = it.duplicate println(it1.foldLeft(0)((c, _) => c+1)) println(it.foldLeft(0)((c, _) => c+1)) println(it2.foldLeft(0)((c, _) => c+1))
こうすると、1回目、3回目で行数が出てくる。
最初の試行と矛盾するような動きだが、こうなっているからこうなっているんだ。Iterator.duplicateのインプリを取り急ぎここに貼り付けておこう。やる気になったら見てみよう。
(githubのここ--> scala/Iterator.scala at v2.11.6 · scala/scala · GitHub )
def duplicate: (Iterator[A], Iterator[A]) = { val gap = new scala.collection.mutable.Queue[A] var ahead: Iterator[A] = null class Partner extends AbstractIterator[A] { def hasNext: Boolean = self.synchronized { (this ne ahead) && !gap.isEmpty || self.hasNext } def next(): A = self.synchronized { if (gap.isEmpty) ahead = this if (this eq ahead) { val e = self.next() gap enqueue e e } else gap.dequeue() } // to verify partnerhood we use reference equality on gap because // type testing does not discriminate based on origin. private def compareGap(queue: scala.collection.mutable.Queue[A]) = gap eq queue override def hashCode = gap.hashCode() override def equals(other: Any) = other match { case x: Partner => x.compareGap(gap) && gap.isEmpty case _ => super.equals(other) } } (new Partner, new Partner) }