Scala Future with Option()



我正在使用future创建三个actor任务,然后在完成后尝试收集所有三个任务。当前代码如下:

implicit val timeout = Timeout(5.seconds)
  val result1 = actor1 ? DataForActor(data)
  val result2 = actor2 ? DataForActor(data)
  val result3 = actor3 ? DataForActor(data)
  val answer = for {
    a <- result1.mapTo[List[ResultData]]
    b <- result2.mapTo[List[ResultData]]
    c <- result3.mapTo[List[ResultData]]
  } yield (a ++ b ++ c).sorted
  answer onComplete {
    case Success(resultData) =>
      log.debug("All actors completed succesffully")
      successActor ! SuccessData(resultData.take(2))
    case Failure(resultData) =>
      log.info("actors failed")
  }

每个参与者(actor1、actor2、actor3)操作数据并返回 None 或 Option(List(resultData)),如以下代码所示:

val resultData = if(data.size == 0) None else {
  data.map {
    ...
    try {
      ... //manipulation on resultData
      Option(resultData)
    }
    catch {
      case e: Exception => None
    }
  }.flatten
}

for 语句连接来自每个参与者的列表,并生成一个长列表(resultData)。

我希望在一个参与者返回 None 的情况下,for 语句中的结果不会向串联添加任何内容,即 List()。

举个例子:

如果我得到: result1 = list(1, 2, 3), 结果2 = 无, result3 = 列表(4, 5),

我想要: 结果数据 = 列表(1, 2, 3, 4, 5)

mapTo这样之前,您可以将None替换为Nil

result1.map{
  case None => Nil
  case x => x
}.mapTo[List[ResultData]]

请注意,您应该避免使用泛型类型mapTo,例如 List

Future("x" :: Nil).mapTo[List[Int]]
// res0: scala.concurrent.Future[List[Int]]
Future("x" :: Nil).mapTo[List[Int]] foreach { _.map( _ + 1 ) }
// java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

由于类型擦除mapTo无法证明您有Int列表,而不是其他类型的List。在演员receive方法中,case l: List[Int]你会遇到同样的问题。

您应该像这样为消息创建特殊类:

sealed trait ResultList { def data: List[ResultData] }
case class NotEmptyResult(data: List[ResultData]) extends ResultList 
case object EmptyResult extends ResultList { def data: List[ResultData] = Nil }
result1.mapTo[ResultList]

最新更新