Chain Scala期货回归类型

时间:2014-09-04 19:01:43

标签: scala future

我试图在Scala中链接Futures,但它给了我错误的返回类型。

我有以下方法:

  def getOneRecordByModel(x:DirectFlight): Future[Option[FlightByDetailModel]] = {
    select.allowFiltering().where(_.from eqs x.from).and(_.to eqs x.to).and(_.departure eqs x.departure).and(_.arrival eqs x.arrival).and(_.carrier eqs x.airline).and(_.code eqs x.flightCode).one()
  }
  def getRecordByUUID(x:FlightByDetailModel): Future[Option[FlightByUUIDModel]] = {
    select.allowFiltering().where(_.uuid eqs x.uuid).one()
  }

  def getUUIDRecordByModel(x:DirectFlight): Future[Option[FlightByUUIDModel]] = {
      getOneRecordByModel(x) andThen {
        case Success(Some(flight)) => getRecordByUUID(flight)
        case Success(x) => Success(x)
        case Failure(x) => Failure(x)
      }
    }

但现在我收到getUUIDRecordByModel返回类型为Future[Option[FlightByDetailModel]]

的错误

如何正确链接它们?

4 个答案:

答案 0 :(得分:8)

我会改用flatMap

def getUUIDRecordByModel(x:DirectFlight): Future[Option[FlightByUUIDModel]] = {
    getOneRecordByModel(x) flatMap {
        case Some(flight) => getRecordByUUID(flight)
        case None => Future.successful(None)
    }
}

andThen应用副作用函数并返回原始 Future,而不是内部函数。

答案 1 :(得分:5)

这个解决方案和上面的2,实际上是相同的。他们提出了flatMaps组成的简单答案。这对于一次性解决方案很有用。

for {
   oUuid <- getOneRecordByModel(x)
   oFlight <- oUuid.map(getRecordByUUID).getOrElse(Future.successful(None))
} yield oFlight

我怀疑给定方法签名,你将会使用这个策略。如果是这种情况,建议使用@Eugene Zhulenev上面的答案(这是一个更实用的解决方案)。思想Monad变形金刚乍一看看起来有点令人生畏,这里有一大堆代码:

val flightByUUID = for {
  flightByDetailModel <- optionT(getOneRecordByModel(x))
  flightByUUIDModel   <- optionT(getRecordByUUID(flightByDetailModel))
} yield flightByUUIDModel

flightByUUID.run  // this line grabs you a Future[Option[T]]

当您开始添加复杂性时,非常简单且可扩展。希望这会对你有所帮助。

答案 2 :(得分:3)

你可以很好地使用scalaz monad变换器,更具体的选项。你可以阅读一套精美的文章,更具体地说,你需要这篇文章:http://eed3si9n.com/learning-scalaz/Monad+transformers.html#Monad+transformers

这个很好:http://noelwelsh.com/programming/2013/12/20/scalaz-monad-transformers/

def getOneRecordByModel(x:DirectFlight): Future[Option[FlightByDetailModel]] = ???
  def getRecordByUUID(x:FlightByDetailModel): Future[Option[FlightByUUIDModel]] = ???

  def getUUIDRecordByModel(x:DirectFlight): Future[Option[FlightByUUIDModel]] = {
    import scalaz.OptionT._

    val flightByUUID = for {
      flightByDetailModel <- optionT(getOneRecordByModel(x))
      flightByUUIDModel <- optionT(getRecordByUUID(flightByDetailModel))
    } yield flightByUUIDModel

    flightByUUID.run
  }

为了能够在scala.concurrent.Future中使用optionT,你需要Functor和Monad实例在范围内

  import scala.concurrent.Future

    object FutureMonadAndFunctor {

    import scalaz.Monad

    implicit def FutureM(implicit ec: ExecutionContext): Monad[Future] = new Monad[Future] {
      def point[A](a: => A): Future[A] = Future(a)
      def bind[A, B](fa: Future[A])(f: (A) => Future[B]): Future[B] = fa flatMap f
    }

    implicit def FutureF(implicit ec: ExecutionContext): Functor[Future] = new Functor[Future]{
      def map[A, B](fa: Future[A])(f: (A) => B): Future[B] = fa map f
    }
  }

  import scala.concurrent.ExecutionContext.Implicits.global

  implicit val F = FutureMonadAndFunctor.FutureF
  implicit val M = FutureMonadAndFunctor.FutureM

答案 3 :(得分:2)

一个简单的解决方案是使用flatMap而不是andThen,它专门用于处理副作用:

getOneRecordByModel(x) flatMap { 
    ...
}

对于处理期货,我发现多次阅读this page会很有帮助。