2015-06-18 2 views
0

У меня с трудом понимается концепция Iteratee/Enumeratee/Enumerator. Похоже, я понял, как создать пользовательский Iteratee - есть несколько хороших примеров, таких как that.Написание пользовательских Enumeratee с Scala и Play2

Теперь я собираюсь написать свой собственный Enumeratee. Я начинаю копать код для этого, существует не так много комментариев там, но много раз (), fold0(), foldM(), joinI(). Я понял, что Enumeratee действительно что-то сделано из Итерате с соусом, но я все еще не могу поймать концепцию написания своего. Итак, если кто-то поможет мне с этой примерной задачей, он даст правильное направление. Давайте рассмотрим такой пример:

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 и т. д.). Как это написать?

P.S. Существует Iteratee, который я написал для подсчета длины каждого фрагмента и в конечном итоге возвращает List [Int]. Может быть, это поможет.

ответ

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] = [email protected] 
repartitionedEnumerator: play.api.libs.iteratee.Enumerator[String] = [email protected] 
lengthEnumerator: play.api.libs.iteratee.Enumerator[Int] = [email protected] 
result1: List[String] = List(abcdef, ghijkl, mnopqrstuvwxyz) 
result2: List[Int] = List(6, 6, 14) 

Enumeratee.grouped мощный метод, который будет группироваться проходимые вещи (Seq, струнных, ...) в соответствии с небольшим внутренним обычаем Iteratee, который Вы определяете. Этот итератор должен потреблять все элементы из потока и создавать элемент, который будет в первом элементе во внешнем enumeratee, а затем будет повторно запущен на оставшемся входе, когда это время для второго внешнего элемента и так далее. Мы достигаем этого, используя специальный вспомогательный метод Enumeratee.splitOnceAt, который делает именно то, что мы ищем, нам просто нужно составить его с помощью простого iteratee, чтобы объединить все эти куски вместе в строку, которая будет возвращена в конце (Iteratee.consume).

Смежные вопросы