我正试图在Play 2中使用Iteratees来传输彗星结果。我有把手从回调中创建一个枚举器,从地图创建一个枚举器。 我的问题是使用Enumeratee.map,这需要一个接受纯输入并返回纯输出的函数(例如doc中的String转换为Int)。我想做的是采取纯粹的输入并返回结果的承诺。 毕竟,枚举器向一个枚举者提供promises,一个枚举器将一个枚举器转换为另一个枚举器,因此应该有一种方法可以生成一个映射到promises的枚举器。
现在,让我举一个例子来说明这一点。假设我有一个http请求,其中包含要在我的数据库中查询的ID列表。假设这些id表示数据库表中的行,并且请求对这些行执行一组(长)计算,然后返回一组表示计算的json对象。 由于我一直在阻止要做的事情,所以一次流式传输一个ID会很酷,所以我希望有一个枚举管道:
1有点容易,我可以构造一个带有fromCallback的枚举器,它将返回查询结果的承诺。 3也很简单,因为它是一个简单的Enumeratee.map
但是我无法理解如何实现第2步的枚举的applyOn。我可以理解我已经构建了一个新的iteratee,它从“内部”迭代中获得了承诺,flatMap the long计算并返回新的承诺。我没有得到的是如何在给出奇怪的applyOn签名的情况下做出这个:def applyOn[A](it: Iteratee[To, A]): Iteratee[From, Iteratee[To, A]]
有人可以帮我吗?
由于
答案 0 :(得分:3)
在主Enumeratee.mapM [E]上有一个方法,它取f:E =>承诺[NE]并返回Enumeratee [E,NE]
答案 1 :(得分:1)
applyOn
的签名更有意义,当您认为枚举者与enumerator |>> (enumeratee &> iteratee)
中的右侧迭代者结合时。 iteratee的类型为Iteratee[E, A]
,枚举器需要Iteratee[Promise[E], Iteratee[E, A]
,以便可以提取内部迭代。因此,applyOn
必须为Iteratee[E, A]
并返回Iteratee[Promise[E], Iteratee[E, A]
。
以下是实施的概要。它定义了一个步进函数,它接受输入并返回预期结果。然后以递归方式逐步执行promise元素。
import play.api.libs.concurrent._
import play.api.libs.iteratee._
def unpromise[E]: Enumeratee[Promise[E], E] = new Enumeratee[Promise[E], E] {
def applyOn[A](inner: Iteratee[E, A]): Iteratee[Promise[E], Iteratee[E, A]] = {
def step(input: Input[Promise[E]], i: Iteratee[E, A]): Iteratee[Promise[E], Iteratee[E, A]] = {
input match {
case Input.EOF => Done(i, Input.EOF)
case Input.Empty => Cont(step(_, i))
case Input.El(pe) =>
val pe2 = pe.map(e => i.feed(Input.El(e))).flatMap(identity)
val i2 = Iteratee.flatten(pe2)
i2.pureFlatFold(
(a, e2) => Done(i2, Input.Empty),
k => Cont(step(_, i2)),
(msg, e2) => Done(i2, Input.Empty))
}
}
// should check that inner is not done or error - skipped for clarity
Cont(step(_, inner))
}
}
我正在放弃e2
,因此可能会有更多代码来确保某些输入不会丢失。