如何在 Scala 中处理嵌套的 Futures Sequence 函数

How to handle nested Futures Sequence functions in Scala

我想创建一个函数,该函数 return 是成功操纵的一系列期货的结果。我遇到的问题是 return 类型是 Unit 并且 future 函数正在完成而无需等待嵌套的 future 序列完成。我试过不使用 onComplete 函数而是使用 map 或 flatMap 但没有成功。我也想避免使用 await

class SquareGenerator(){
  //if type is changed to Unit anything that calls this function receives a empty success
  def getSquare() : Future[Int] = Future{
    val sums = List(future1(), future2())

    val results = Future.sequence(sums)

    //compiler throws an error because this is returning a unit
    results.onComplete({ 
      case Success(result) =>{
        val sum = result(0) + result(1)
        sum * sum
      }
    })
  }

  private def future1() : Future[Int] = Future{
    //do something that takes time
    2
  }

  private def future2() : Future[Int] = Future{
    //do something that takes time
    3
  }
}

以后会这样称呼

val squareGenerator = new SquareGenerator()
squareGenerator.getSquare().onComplete({
  case Success(result) =>{
    //do something with result
  }
  case Failure(e){//log failure}
})

只是return这里的未来

def getSquare : Future[Future[List[Int]]] = Future{
    val sums = List(future1(), future2())
    Future.sequence(sums)
  }

并且,当您调用它时,检查结果的完成

  squareGenerator.getSquare.onComplete({
    case Success(result) =>
      result.onComplete({
        case Success(result) => {
          val sum = result(0) + result(1)
          val square = sum * sum
          println(square)
        }
      })

    case Failure(e) => {
      //log failure
    }
  })

而不是 onComplete 你应该这样做:

results.map{ result => 
                val sum = result(0) + result(1)
                sum * sum
            }.recover { case e => ...
                // write to log, throw e, or return the same type of sum
}

map可以转换Future里面的return类型,以后只有成功完成才会returned。

这就是为什么你需要添加 recover 来处理 future 失败的情况。

如果你这样做,你将不需要函数开头的 Future,因为你不需要创建一个新的 Future - 你将使用 Future 来自 results.

onComplete 生成 Unit。您想要 mapflatMap 或其他实际产生值的东西。

  def getSquare() : Future[Int] = {
    val sums = List(future1(), future2())

    val results: Future[List[Int]] = Future.sequence(sums)

    results.map {
      result => 
        val sum = result(0) + result(1)
        sum * sum
    }
  }

使用数组索引不安全。为了安全起见,您可以使用折叠或模式匹配。

    results map {
      case m :: n :: Nil =>
        val sum = m + n
        sum * sum
      case _ =>
        println("did not get 2 numbers!")
        0
    }

你应该使用 map/flatmap 或理解。

def getSquare() : Future[Int] = 
  for {
    res1 <- future1()
    res2 <- future2()
  } yield {
    val sum = res1 + res2
    sum * sum
  }

for comprehension 是 map 和 flatmap 的便捷包装。在 for 部分,您需要将期货结果分配给变量,稍后您可以在 yield 部分对它们进行操作。