2014-10-10 23 views
0

我有一个列表的东西,让我们只是说字符串。
我想将它转换成事物的Future [List],让我们再来说一下Strings。
并行执行是不是通缉。Scala/Play:从(部分)列表中创建未来[列表[...]]

这将最终在一个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) 
    } 
} 

在我想回到一个未来到底[列表[...],包括第一个失败的结果,然后停止。
可以简化为这样:

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) 
    } 

,一切事都处理的顺序很重要。

这样工作,但我真的想摆脱“Await.ready”。

我希望我的问题很清楚,目前我无法将我的头围绕在此。

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

调用应该返回

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

回答

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全部来自handle失败Future S,含有异常消息成功的取代了它们。如果您希望整个Future[List[String]]在一个错误输入上失败,您可以从链中删除recover

+0

这是非常接近的,但其实我是想的处理第一次失败后停止。 (虽然仍然提供达到这一点的结果!) – Andreas 2014-10-10 15:25:08

0

我建议处理您的成功,或失败与Either(或scalaz \/),并为意外故障保留Future.failure,以同样的方式,很多人建议不要使用例外“正常”控制流。那么你的返回值可以有一个明智的类型,而不是随机包含String s和Throwable s的List

import scalaz._, Scalaz._ 
import scala.concurrent.Future, scala.concurrent.ExecutionContext.Implicits.global //or your own execution context 

case class MyError(input: String) 

def handle(input: String): Future[ MyError \/ String ] = 
    input match { 
    case "X" => MyError(input).left 
    case other => Future.successful(("handled "+other).right) 
    } 

def handleInOrder(inputs: List[String]): Future[(List[String], MyError) \/ List[String]] = 
    inputs.foldLeftM(List().right: (List[String], MyError) \/ List[String]) { 
    (acc, input) => acc match { 
     case -\/(alreadyFailed) => Future.successful(-\/(alreadyFailed)) 
     case \/-(successfulSoFar) => 
     handle(input) map { 
      case \/-(alsoSuccessful) => \/-(alsoSuccessful :: successfulSoFar) 
      case -\/(nowFailed) => -\/((successfulSoFar, nowFailed)) 
     } 
     } 
    } 
+0

你显然是对的。在实际的代码中我完全是这样做的(Right(result),Left(error),Failure(critical))。上面的示例中,我将其简化为过分简化。谢谢! – Andreas 2014-10-12 07:45:12

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) 
}