使用Scala和Play2编写自定义枚举

时间:2015-06-18 18:46:29

标签: scala playframework-2.0 iterate

我很难理解Iteratee / Enumeratee / Enumerator概念。看起来我理解如何创建自定义Iteratee - 有一些很好的例子,如that

现在我要写我的自定义Enumeratee。我开始为此挖掘代码,那里没有那么多评论,但有很多 fold() fold0() foldM() joinI()。我知道Enumeratee真的是由Iteratee制作的酱汁,但我仍然无法捕捉到写自己的概念。所以,如果有人帮我完成这个示例任务,它将给出正确的方向。让我们考虑这样的例子:

val stringEnumerator = Enumerator("abc", "def,ghi", "jkl,mnopqrstuvwxyz")
val myEnumeratee: Enumeratee[String, Int] = ... // ???
val lengthEnumerator: Enumerator[Int] = stringEnumerator through myEnumeratee // should be equal to Enumerator(6, 6, 14)

myEnumeratee 应该通过用逗号分割给定的字符流并返回每个块的长度来重新取样流(" abc" +" def"长度为6,& #34; ghi" +" jkl"长度为6,依此类推)。怎么写呢?

P.S。 我写了一个Iteratee用于计算每个块的长度并最终返回List [Int]。也许它会有所帮助。

1 个答案:

答案 0 :(得分:1)

你在这里尝试做的奇特事情是重新分配字符,而不是根据它们先前存在的迭代Input边界,而是用逗号边界。之后就像编写Enumeratee.map{_.length}一样简单。以下是在粘贴模式下使用scala解释器的示例。您可以看到底部的result1是重新分区的字符串,result2只是每个字符串的计数。

scala> :paste
// Entering paste mode (ctrl-D to finish)

import play.api.libs.iteratee._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

def repartitionStrings: Enumeratee[String, String] = {
  Enumeratee.grouped[String](Traversable.splitOnceAt[String, Char](c => c != ',') transform Iteratee.consume())
}

val stringEnumerator = Enumerator("abc", "def,ghi", "jkl,mnopqrstuvwxyz")

val repartitionedEnumerator: Enumerator[String] = stringEnumerator.through(repartitionStrings)
val lengthEnumerator: Enumerator[Int] = stringEnumerator.through(repartitionStrings).through(Enumeratee.map{_.length}) // should be equal to Enumerator(6, 6, 14)

val result1 = Await.result(repartitionedEnumerator.run(Iteratee.getChunks[String]), 200 milliseconds)
val result2 = Await.result(lengthEnumerator.run(Iteratee.getChunks[Int]), 200 milliseconds)

// Exiting paste mode, now interpreting.

import play.api.libs.iteratee._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._
repartitionStrings: play.api.libs.iteratee.Enumeratee[String,String]
stringEnumerator: play.api.libs.iteratee.Enumerator[String] = play.api.libs.iteratee.Enumerator$$anon$19@77e8800b
repartitionedEnumerator: play.api.libs.iteratee.Enumerator[String] = play.api.libs.iteratee.Enumerator$$anon$3@73216e8d
lengthEnumerator: play.api.libs.iteratee.Enumerator[Int] = play.api.libs.iteratee.Enumerator$$anon$3@2046e423
result1: List[String] = List(abcdef, ghijkl, mnopqrstuvwxyz)
result2: List[Int] = List(6, 6, 14)

Enumeratee.grouped是一个强大的方法,它将根据您定义的一个小的内部自定义Iteratee将可遍历的东西(Seq,String,...)组合在一起。这个iteratee应该使用流中的所有元素并生成将在外部枚举中的第一个元素中的元素,然后在第二个外部元素的时间时重新运行剩余的输入,依此类推。我们通过使用特殊的帮助方法Enumeratee.splitOnceAt来实现这一点,它正是我们正在寻找的,我们只需要用一个简单的迭代来组合它,将所有这些块连接成最后将返回的字符串({ {1}})。