如何组合两个 Future[JsArray]?

How can I combine two Future[JsArray]?

我有两个Future[JsArray]f1f2,我需要等待两个都完成并得到结果。

如果他们都成功了,最后的结果应该是Success保存他们内容的总和。如果 then 中至少有一个失败,则最终结果应该是 Failure.

我该怎么做?

您可以使用 'for' 语法组合期货。类似于:

val f1:Future[Int] = getF1()
val f2:Future[Int] = getF2()
val res:Future[Int] = for (
  v1 <- f1;
  v2 <- f2
) yield (v1 + v2)

假设 "summing arrays" 你的意思是将它们与 ++ 连接起来,你想要做的是:

Future.sequence(Set(getF1,getF2)) map { _ reduce(_ ++ _)}

当且仅当所有未来都成功时,序列才会成功。然后我们通过 ++-ing 其所有元素来减少结果 Set

一个解决方案

  1. Future 定义一个 map2 函数:

    def map2[A, B, C](fa: Future[A], fb: Future[B])(g: (A, B) => C)
                     (implicit executor: ExecutionContext): Future[C] =
      for {
        a <- fa
        b <- fb
      } yield g(a, b)
    
  2. 定义一个 merge 函数来合并两个 JsArray(即提取和连接 元素 ,并使用结果创建一个新的 JsArray):

    def merge(array1: JsArray, array2: JsArray): JsArray =
      JsArray(array1.elements ++ array2.elements: _*)
    

    注意:您需要类型归属才能将结果 Vector 传递给 JsArray's apply method

  3. 通话

    map2(f1, f2)(merge)
    

在 REPL

中试用 运行
scala> import spray.json._
import spray.json._

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> val f1 = Future(JsArray(JsNumber(1), JsNumber(2))) 
f1: scala.concurrent.Future[spray.json.JsArray] = List()

scala> val f2 = Future(JsArray(JsNumber(3), JsNumber(4), JsNumber(5)))
f2: scala.concurrent.Future[spray.json.JsArray] = List()

scala> map2(f1, f2)(merge).onComplete(println)
Success([1,2,3,4,5])

直接而简单的解决方案

Future支持zip操作,非常方便

val f1: Future[JsArray]
val f2: Future[JsArray]
val resultF = f1.zip(f2).map {case (a, b) =>  a ++ b}

如果 f1f2 失败,resultF 也会失败,与 f1f2 失败相同。

您可以选择删除括号

val resultF = f1 zip f2 map { case (f1Result, f2Result) => f1Result ++ f2Result }