Как соединить два Scala Futures - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть две функции 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]].Я знаю, это потому, что я передаю одно Будущее другому, но я не знаю, как правильно соединить эти два Будущего, избегая использования Await.Я остановлюсь явно использовать Await, тогда каково будет решение?

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Вам не нужны монадные трансформаторы и другая «тяжелая артиллерия» для таких простых вещей, как это.Общее правило: не делайте ваш код более сложным, чем он должен быть.

 (parseIntFuture(foo) zip parseIntFuture(bar))
   .flatMap {
     case (Some(a), Some(b)) => divideFuture(a, b) 
     case _ => Future.successful(None)
   }
0 голосов
/ 20 декабря 2018

Существует то, что называется OptionT монадный трансформатор , который решает именно эту проблему.С 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]].


. Вы можете избежать монадных преобразователей за счет вложенных для-пониманий:

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
}
...