Scala / Play:从(部分)列表创建未来[List [...]] [...]

时间:2014-10-10 14:56:35

标签: scala playframework-2.0

我有一份事情清单,让我们说一下字符串 我想把它变成一个Future [List []]的东西,让我们再说一下Strings 并行执行需要。

这将以Action.async结束,因此不欢迎阻止。

我有一个可以在将来转换元素的处理程序 简化为:

def handle( input: String ): Future[ String ] =
{
  input match {
    case "X" => Future.failed( new Exception( "failed on "+input ) )
    case other => Future.successful( "handled "+other )
  }
}

最后,我想返回一个Future [List [...]],包括第一个失败的结果,然后停止 可以简化为:

  def handleInOrder( inputs: List[ String ] ): Future[ List[ String ] ] = {
    val output = new ListBuffer[ String ]( )
    breakable { for( input <- inputs ){
      Await.ready( handle( input ), Duration.Inf ).value.get match {
        case Success( result ) => output += result;
        case Failure( reason ) => output += "Ex:"+reason; break
      }
    } }

    Future.successful( output.toList )
  }

处理事情的顺序很重要。

这样可以正常工作,但我真的想摆脱这种情况&#34; Await.ready &#34;。

我希望我的问题很清楚,目前我无法解决这个问题。

致电

handleInOrder( List( "a", "b", "X", "c" )

应该返回

List(handled a, handled b, Ex:java.lang.Exception: failed on X)

3 个答案:

答案 0 :(得分:0)

您可以使用foldLeft按顺序执行Future

def handleInOrder(inputs: List[String]): Future[List[String]] = {
    inputs.foldLeft(Future.successful(ListBuffer.empty[String])) { case (acc, next) => 
        handle(next).recover { case t: Throwable => "Ex: " + t.getMessage}
            .flatMap(f => acc.map(_ += f))            
    }.map(_.toList)
}

这将recover Future handle来自Future[List[String]],并将其替换为包含异常消息的成功消息。如果您希望整个recover在一个错误输入上失败,则可以从链中删除{{1}}。

答案 1 :(得分:0)

我建议使用Either(或scalaz \/)来处理您的成功或失败,并为意外失败保留Future.failure,就像很多人建议的那样不要对“正常”控制流使用例外。然后,您的返回值可以是合理的类型,而不是随机包含ListString的{​​{1}}。

Throwable

答案 2 :(得分:0)

这将在第一次失败时停止:

def handleInOrder(inputs: List[String]): Future[List[String]] = {
  def run(inputs: List[String], output: ListBuffer[String]): Future[ListBuffer[String]] = inputs match {
    case h :: t => handle(h).flatMap{x => run(t, output += x)}.recover{ case t: Throwable => output += ("Ex: " + t.getMessage)}
    case _ => Future { output }
  }
  run(inputs, ListBuffer.empty[String]).map(_.toList)
}