Почему мой takeWhile не работает с моим потоком - PullRequest
10 голосов
/ 28 октября 2011

Следующий код выводит «* 1». Что удивительно, если я удаляю комментарий, он возвращает «* 4», что я и ожидал

var max = 0
lazy val list: Stream[Int] = 1 #:: Stream.from(2)
list.takeWhile {
  x =>
    max = x
    x < 4
}//.foreach(println)
println("*" + max)

1 Ответ

20 голосов
/ 28 октября 2011

Прежде всего: lazy во второй строке ничего не делает - вы можете удалить его и получить тот же результат.

Что еще более важно: takeWhile это на самом деле ленивый, поскольку он просто возвращает еще один Stream, и ничто за пределами этого потока не будет оцениваться до тех пор, пока оно не потребуется. Учтите следующее:

val s = Stream.from(1).takeWhile(_ > 0)

Мы с вами знаем, что s будет бесконечным потоком, но если мы запустим REPL и введем его, он будет очень счастлив оценить его:

scala> val s = Stream.from(1).takeWhile(_ > 0)
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)

То же самое происходит в вашем примере: (Int) ⇒ Boolean, который вы передали takeWhile, не получит питание от каких-либо элементов за пределами головы потока, пока что-то вроде вашего foreach не сделает это необходимо.

Вы можете увидеть это еще более драматично, добавив что-то вроде println внутри предиката takeWhile:

scala> val s = Stream.from(1).takeWhile { x => println("Checking: " + x); x < 4 }
Checking: 1
s: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> val l = s.toList
Checking: 2
Checking: 3
Checking: 4
l: List[Int] = List(1, 2, 3)

Очевидно, что предикат вызывается только для заголовка потока, пока мы не вызовем оценку остальной части потока, вызвав toList.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...