Nieco prostopadle, to zachowanie można osiągnąć stosując współprogram. Istnieje co najmniej jedna biblioteka dla Scala, który umożliwia współprogram, można go znaleźć tutaj: http://storm-enroute.com/coroutines/
Oto przykład kodu będziesz pisać to, co chcesz:
import org.coroutines._
def sideEffectingFunction = coroutine {() =>
val limit = new scala.util.Random().nextInt(10)
val seq = new scala.util.Random
var counter = 0 // mutable state is preserved between coroutine invocations
while (counter < limit) {
counter += 1
yieldval(seq.nextInt)
}
}
defined function sideEffectingFunction
@ val cr = call(sideEffectingFunction())
cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true>
@ cr.resume
res31: Boolean = true
@ cr.value
res32: Int = 57369026
@ cr.resume
res33: Boolean = true
@ cr.value
res34: Int = -1226825365
@ cr.resume
res35: Boolean = true
@ cr.value
res36: Int = 1304491970
@ cr.resume
res37: Boolean = false
@ cr.value
java.lang.RuntimeException: Coroutine has no value, because it did not yield.
scala.sys.package$.error(package.scala:27)
org.coroutines.Coroutine$Frame$mcI$sp.value$mcI$sp(Coroutine.scala:130)
cmd38$.<init>(Main.scala:196)
cmd38$.<clinit>(Main.scala:-1)
Lub alternatywnie:
@ val cr = call(sideEffectingFunction())
cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true>
@ while(cr.resume) println(cr.value)
-1888916682
1135466162
243385373
Albo, w duchu poprzedniej odpowiedzi:
@ val cr = call(sideEffectingFunction())
cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true>
@ cr.resume
res60: Boolean = true
@ val iter = Iterator.continually(cr.value).takeWhile(_ => cr.resume)
iter: Iterator[Int] = non-empty iterator
@ iter.foreach(println)
1595200585
995591197
-433181225
220387254
201795229
754208294
-363238006
T Zaletą podejścia typu coroutines jest to, że możesz zachować zmienny stan między inwokacjami funkcji leżących u podstaw funkcji, które są dobrze ukryte przed światem zewnętrznym wewnątrz korupcji. Coroutines można również komponować i nawzajem się nawzajem.
Oczywiście, Coroutines dają o wiele więcej mocy niż tylko wykonywanie zadania, więc może to być przesada, aby dodać je tylko do tego. Jednak jest to przydatna technika, aby być świadomym.
Wielkie dzięki za doskonałą i szybką odpowiedź! – satyagraha
Ostateczny '.map (_. Get)' może w ostatnich wersjach Scala zostać zastąpiony przez '.flatten', który wprowadza niejawny TraversableOnce CBF i powiązany iterator. Myślę, że to nadal spełnia moje kryteria. – satyagraha
Masz rację. Tęskniłem za tym, ponieważ skaladoc dla "Iteratora" nie wspomina o tym. Wygląda jak błąd skaladoc: 'flatten' pochodzi z klasy enrichement' TraversableOnce.FlattenOps' i enrichements mają być obsługiwane przez skaladoc (i wiele z nich). Zaktualizowałem swoją odpowiedź. –