Scala:递归使用Future

时间:2015-03-19 03:49:42

标签: scala future scala-collections

我试图弄清楚如何以递归方式使用Scala Futures。我的用例是将资源(ResourceOne)的输出与另一个资源(ResourceTwo)输出进行比较,如果在我想要同步第一个资源(ResourceOne)并再次检索资源的过程中它们之间存在任何差异。我从resourceOne检索的项目数与resourceTwo同步。但是由于我的操作(检索和删除)与ResourceOne返回Future,我陷入了逻辑的一半。下面是一个说明我的问题的示例,对于完成步骤#3和#4以及在步骤#5中递归#1到#4的任何想法?

package com.example

import scala.concurrent.Future
import scala.collection.mutable.Map
import scala.concurrent.ExecutionContext.Implicits.global

object ResourceOne {

  //var resources = List("one", "two","three","four","five","six","seven","eight","nine")
  var resources = List("one", "two","three")

  def getFirstFive():Future[List[String]] = Future {
    resources.take(5)
  }

  def remove(res:String) = Future {
    println(s"Deleting ${res}")
    resources = resources.filter( ! _.equals(res) )
  }
}

object ResourceTwo {

  val resourceDetails = Map("one" ->"oneDetail", "three" -> "threeDetail","four" ->"fourDetails","six" -> "sixDetail", "eight" -> "eightDetail")

  def getResourceDetail(resource:String) = {
    resourceDetails.get(resource);
  }
}

object HelloFuture {

  def main(args: Array[String]): Unit = {

    println("1. Fetching first five")
    val resF = ResourceOne.getFirstFive()

    println("2. Retrieving the resource detail from ResourceTwo, if a resourceDetail does not exist then delete the resource from resourceOne")
    val resFOut = resF.map( resList => {
        resList.map( resOne => {
            val resOneDetail = ResourceTwo.getResourceDetail( resOne )
            //println(s"Resource details for ${resOne} is ${resOneDetail}")
            if( resOneDetail == None) {
                println("2.a delete resource if detail is not available")
              ResourceOne.remove(resOne)
            }
          })
      })

    println("3. Verifying if all the resources retrieved from resourceOne were available in resourceTwo or not.")
    //TODO

    println("4. If all were not available then retrieve from resourceOne again as the missing ones will have been deleted.")
    //TODO

    println("5. Repeat step 1 thru 4 till all resources retreived from resourceOne are available in resourceTwo.")    

  }
}

1 个答案:

答案 0 :(得分:0)

环顾四周之后想出了以下解决方案。但是这个问题存在一个小问题,ResourceOne.remove()返回一个未来,下面的实现不能很好地处理它,导致fetchResource()运行几次,直到ResourcesOne.remove()完成。不确定如何处理。

package com.example

import scala.concurrent.Future
import scala.util.{Success,Failure}
import scala.collection.mutable.Map
import scala.concurrent.ExecutionContext.Implicits.global

object ResourceOne {

  //var resources = List("one", "two","three","four","five","six","seven","eight","nine")
  var resources = List("one", "two","three")

  def getFirstFive():Future[List[String]] = Future {
    resources.take(5)
  }

  def remove(res:String) = Future {
    println(s"Deleting ${res}")
    resources = resources.filter( ! _.equals(res) )
  }
}

object ResourceTwo {

  val resourceDetails = Map("one" ->"oneDetail", "three" -> "threeDetail","four" ->"fourDetails","six" -> "sixDetail", "eight" -> "eightDetail")

  def getResourceDetail(resource:String) = {
    resourceDetails.get(resource);
  }
}

object HelloFuture {

  def main(args: Array[String]): Unit = {

    val fOut = fetchResource()
    fOut.map{ detail => println("Final Detail retreived is "+ detail) }

  }

  // Gets from resourceOne and if the detail is not found in resourceTwo then deletes from resourceOne and refetches from resourceOne till both the fetches match
  def fetchResource():Future[List[Any]] = {
    println("Fetching first five")
    val resF = ResourceOne.getFirstFive()

    var resOneCount = 0;
    val resFOut = resF.map( resList => {
        resList.map( resOne => {
            val resOneDetail = ResourceTwo.getResourceDetail( resOne )
            resOneCount += 1
            resOneDetail match {
              case Some(_) => { resOneDetail }
              case None =>  { ResourceOne.remove(resOne) ; resOneDetail }
            }
          })
      })

    resFOut flatMap {
      case  x if x.filter(_ != None).size == resOneCount => Future.successful(x)
      case _ => {  fetchResource() }
    }
  }

}