如何连接两个Scala期货

时间:2018-12-20 16:07:54

标签: scala future

我有两个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来将这两个Future逐一连接的正确方法是什么。我暂停使用Await,那么解决方案是什么?

2 个答案:

答案 0 :(得分:6)

对于像这样的简单东西,您不需要monad变压器和其他“重型大炮”。一般规则是,不要使您的代码比绝对必要的复杂。

public extension Data {  

    //MARK: - Public  
    public mutating func extractSubDataWith(range: Range) -> Data? {  

        guard range.lowerBound >= 0 && range.upperBound <= self.count else {  
            return nil  
        }  

        // Get a copy of data and remove them from self  
        let subData = self.subdata(in: range)  
        self.removeSubrange(range)  

        return subData  
    }  
}  

答案 1 :(得分:5)

有一个叫做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]]


您可以避免使用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
}