【问题标题】:Writing custom Enumeratee with Scala and Play2使用 Scala 和 Play 2 编写自定义枚举
【发布时间】:2015-09-04 13:32:29
【问题描述】:

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

现在我要编写我的自定义 Enumeratee。我开始为此挖掘代码,那里没有那么多 cmets,而是很多 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,“ghi”+“jkl”长度为 6 和很快)。怎么写?

附: 我写了一个 Iteratee 来计算每个块的长度并最终返回 List[Int]。也许会有所帮助。

【问题讨论】:

    标签: scala playframework-2.0 iterate


    【解决方案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、...)组合在一起。此迭代器应消耗流中的所有元素并生成将在外部枚举器中的第一个元素中的元素,然后在第二个外部元素时在剩余的输入上重新运​​行,依此类推。我们通过使用特殊的帮助方法 Enumeratee.splitOnceAt 来实现这一点,它正是我们正在寻找的,我们只需要用一个简单的 iteratee 组合它,将所有这些块连接在一起成为最后返回的字符串 (@ 987654325@)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多