2015-08-06 3 views
2

Я удаляю конечную точку HTTP, которая возвращает разбитый на панель ответ JSON. Значение «meta.next» в моем типе ответа указывает на следующую страницу ответа. Когда это значение равно NULL, больше нет страниц для извлечения. Я использую Spray IO для создания HTTP-запросов. Я собираю записи, представляющие интерес в каждом ответе на странице , и объединяйте их с тем, что было собрано до сих пор. Когда следующий становится null, я возвращаю все собранные записи. Мой вопрос: Есть ли способ сделать функцию getJson (...) ниже хвоста рекурсивной?Может ли это быть регенерированным хвостом?

case class JsonResponse(meta: Meta, items: List[Item]) 

val pipeline: Future[HttpRequest => Future[JsonResponse]] = for (
    Http.HostConnectorInfo(connector, _) <- 
    IO(Http) ? Http.HostConnectorSetup("somehost.com", port = 80) 
) yield sendReceive(connector) ~> unmarshal[JsonResponse] 


    // ..... 

    def getJson(relativeUrl: String)(implicit m: Monoid[Future[List[JsObject]]]) : Future[List[JsObject]] = { 

    val jsr = pipeline.flatMap(_(Get(relativeUrl))) 

    // Grab only those entries that we are interested in 
    val objList = jsr.map(js => js.items.collect{ case o if(o.whatever.isDefined) => o.toJson.asJsObject }) 

    jsr.flatMap(js => js.meta.next.map(next => m.append(getJson(next), objList)).getOrElse(objList)) 
    } 

ответ

3

Репликация хвоста здесь не применима. Когда вы используете будущие комбинаторы, вы не работаете в одном стеке.

Конкретно, getJson немедленно возвращается в каждом случае. Используя jsr.flatMap, вы регистрируете обратный вызов, который будет вызываться только тогда, когда был получен ответ для HTTP-запроса. Следовательно, следующий вызов getJson также произойдет в этом контексте, то есть в стеке обратного вызова, предоставляемом контекстом неявного исполнения.

Таким образом, хотя рекурсия все еще происходит на алгоритмическом уровне, это не приводит к складыванию кадров стека в стек одного (или любого) потока.

Что касается продувки стека, ваш код в порядке. Есть ли еще одна причина, по которой вы хотите использовать хвостовую рекурсию?

+0

Ah. Спасибо! Да, единственная причина, по которой я хотел использовать хвостовую рекурсию, - это страх выдувать мой стек. Это может привести к обработке многих страниц перед возвратом. Большое спасибо за ваше четкое объяснение. Теперь я чувствую себя немного глупым, потому что не понимаю этого, но также очень облегчен. –

+0

Нет, беспокоится. Такие мощные, как «Будущие», являются новым общим асинхронным примитивом выполнения, поэтому трудно вначале понять, как выполнение выполняется во всех различных сценариях. – jrudolph

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