2014-09-04 204 views
7

我想鏈接在斯卡拉期貨,但它給了我錯誤的返回類型。鏈斯卡拉期貨返回類型

我有以下幾種方法:

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]]

如何正確地把它們連?

+0

當你使用和然後你不改變返回類型。你想要flatMap或map取決於另一種方法的返回類型。 – monkjack 2014-09-04 19:31:44

+2

'和Then' combinator純粹是爲了副作用。它始終返回它未被調用的「未來」,保持不變。正如其他人所說,「map」和/或「flatMap」應該是你正在尋找的。 – cmbaxter 2014-09-04 19:46:50

回答

8

我會用flatMap來代替。

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

andThen施加副作用的函數,並返回原來Future,而不是內之一。

+0

就是這樣。非常感謝你! – elmalto 2014-09-04 20:32:18

3

你可以用scalaz monad變形器,optionT更好地做到這一點。您可以蘆葦組漂亮的文章,更具體的,你需要這一個: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 
    } 

爲了能夠使用optionT與scala.concurrent.Future你需要函子和單子實例是在範圍

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 
+0

謝謝你的洞察力。我已經多次遇到斯卡拉茲了。我想是我該做一些學習的時候了。 – elmalto 2014-09-04 20:35:27

2

一個簡單的解決方案是使用用於flatMap組合物代替andThen,這是相當專用於處理副作用:

getOneRecordByModel(x) flatMap { 
    ... 
} 

爲了與期貨合作,我發現多次閱讀this page很有幫助。

5

該解決方案和上面的2實際上是相同的。他們提出了flatMaps組成的簡單答案。這對於一次性解決方案很有用。

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

我懷疑給定的方法簽名,你將會使用這個策略很多。如果是這樣的話,建議@Eugene Zhulenev的回答如上(這是一個功能更強大的解決方案)。以爲單子變壓器可以看看乍一看有點嚇人,代碼這裏的塊:當你開始增加複雜性

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

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

是非常簡單的,可擴展的。希望這可以幫助你。

+0

的作品以及非常感謝你。不幸的是,我只能選擇一個正確的答案。 – elmalto 2014-09-04 20:33:39