我有一个东西列表,让我们说字符串。
我想把它转换成一个未来[列表[ ]]的东西,让我们再说字符串。
不需要并行执行。
这将最终出现在 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[ 列表[ ... ] ],包括第一个失败的结果,然后停止。
可以简化为:
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)
您可以使用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
,将它们替换为包含异常消息的成功。如果你想让整个Future[List[String]]
在一个错误的输入上失败,你可以从链中删除recover
。
我建议使用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))
}
}
}
这将在第一次失败时停止:
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)
}