【问题标题】:How to connect two Scala Futures如何连接两个 Scala 期货
【发布时间】:2019-05-21 04:25:25
【问题描述】:

我有两个 Future 函数:

def parseIntFuture(str: String) = Future{scala.util.Try(str.toInt).toOption}
def divideFuture(a: Int, b: Int) = Future{ if (b == 0) None else Some(a / b)}

现在我想连接它们并最终得到Future[Option[Int]] 类型的结果,这是第二个返回值,但如果我这样做:

def stringDivideBy(aStr: String, bStr: String) = {
    val x = for {
        aNum <- parseIntFuture(aStr)
        bNum <- parseIntFuture(bStr)
    } yield (aNum, bNum)

    x.map(n => {
        for{
            a <- n._1
            b <- n._2
        } yield divideFuture(a, b)
    })
}

实际上我会得到Future[Option[Future[Option[Int]]]] 而不是Future[Option[Int]]。我知道这是因为我将一个 Future 传递给另一个,但我不知道将这两个 Future 一个一个连接起来的正确方法是什么,避免使用 Await。我停止显式使用 Await,那么解决方案是什么?

【问题讨论】:

    标签: scala future


    【解决方案1】:

    对于像这样的简单东西,您不需要单子转换器和其他“重型火炮”。一般规则是不要让你的代码比它绝对必须的更复杂。

     (parseIntFuture(foo) zip parseIntFuture(bar))
       .flatMap {
         case (Some(a), Some(b)) => divideFuture(a, b) 
         case _ => Future.successful(None)
       }
    

    【讨论】:

    • ...它还具有zip 不会强制ab 按顺序排列的优点。不错。
    【解决方案2】:

    有一个叫做OptionT monad transformer 的东西正好解决了这个问题。使用OptionT,您的代码看起来有点像

    import cats.data.OptionT
    
    // ...
    
    val x = (for {
        aNum <- OptionT(parseIntFuture(aStr))
        bNum <- OptionT(parseIntFuture(bStr))
        res <- OptionT(divideFuture(aNum, bNum))
    } yield res).value
    

    并返回Future[Option[Int]]


    您可以以嵌套 for-comprehensions 为代价来避免使用 monad 转换器:

    import scala.concurrent._
    import scala.concurrent.ExecutionContext.Implicits.global
    
    def parseIntFuture(str: String) = Future{scala.util.Try(str.toInt).toOption}
    def divideFuture(a: Int, b: Int) = Future{ if (b == 0) None else Some(a / b)}
    
    def stringDivideBy(aStr: String, bStr: String): Future[Option[Int]] = {
      for {
        aOpt <- parseIntFuture(aStr)
        bOpt <- parseIntFuture(bStr)
        resOpt <- 
          (for {
            a <- aOpt
            b <- bOpt
          } yield divideFuture(a, b))
          .getOrElse(Future { None })
      } yield resOpt
    }
    

    【讨论】:

      猜你喜欢
      • 2019-09-01
      • 1970-01-01
      • 2019-05-12
      • 2015-04-23
      • 2022-01-22
      • 2018-06-15
      • 2021-03-17
      • 2020-11-05
      • 2017-03-30
      相关资源
      最近更新 更多