Scala итератор и поток. поток не используется при повторном использовании

У меня есть код (sentences is iterator здесь):

  def count() = {
    var count = 0
    for(sentence <- sentences.toStream) count += sentence.words.size
    count
  }

и тест:

// first
val wordCount1 = wordCounter.count()
wordCount1 must_== 10

// second time - should be same result
val wordCount2 = wordCounter.count()
wordCount2 must_== 10   // fails: result is 0

Последний тест не выполнен:

'0' is not equal to '10'
Expected :10
Actual   :0

Но так как я использую sentences.toStream в приведенном выше коде, я полагаю, что в нем есть stream (я могу его повторно использовать, теоретически).

Q: почему это не удается?


EDIT: Я надеялся, что toStream поможет. Как описано здесь: (... "Вы можете пройти один и тот же stream несколько раз"...). Как будто я никогда не касаюсь итератора, у меня есть дело с потоком.

Но я получил.. sentences.toStream использовал UP sentence-iterator, поэтому я больше не могу его использовать. Я просто ожидал, когда toStream на iterator выполняет логику, как получение stream-'link 'для итератора, не касаясь самого итератора. Ok..

Ответ 1

Он терпит неудачу, потому что был израсходован sentences Iterator. Один из них не должен вызывать Iterator после того, как метод на нем был вызван, за исключением методов next и hasNext.

Простой пример показывает это:

scala> val it = Iterator(1,2,3)
it: Iterator[Int] = non-empty iterator

scala> it.foreach(println(_))
1
2
3

scala> it.foreach(println(_))

scala> 

В вашем случае sentences был израсходован на первый вызов и пуст на втором, указав размер 0.

Вызов toStream на нем не изменит этого. Вы возвращаетесь пустым Stream. Если вы хотите повторно использовать sentences назначить его списку с val l = sentences.toList перед вызовом счетчика.

Ответ 2

Фактически toStream помогает. Я просто изменил код, чтобы ожидать stream, но не iterator, чтобы не пытаться создать поток из "мертвого" итератора на втором + траверсе.

Тогда мое решение:

val stream = new SentenceFileReader("two_lines_file.txt").toStream

val wordCounter = new WordCounter(stream) // now it accepts stream but not iterator

// first
val wordCount1 = wordCounter.count()
wordCount1 must_== 10

// second time - same result
val wordCount2 = wordCounter.count()
wordCount2 must_== 10