我怎样才能修复"这个回复,我想要Future [Option [F4]]
val f4Response: Future[Option[Future[Option[Future[F4]]]]] =
for {
f1Opt <- api.getF1() // Future[Option[F1]]
f2Opt <- if (f1Opt.isDefined) api.getF2(f1Opt.get.id) else Future.successful(None) // getF2 is Future[Option[F3]]
} yield {
for {
f1 <- f1Opt
f2 <- f2Opt
} yield {
for {
f3Opt <- api.getF3(f1.id, f2.id) // Future[Option[F3]]
} yield {
for {
f3 <- f3Opt
} yield {
api.insertF(f1, f2, f3) // Future[Option[F4]]
}
}
}
}
更新
我试图使用scalaz但是我收到了错误:
val result: Future[Option[f4]] = (
for {
f1 <- OptionT(api.getF1(..))
f2 <- OptionT(api.getF2(..))
f3 <- OptionT(api.getF3(f1.id, f2.id)
} yield api.getF4(f1, f2, f3)
).run
错误是:
[error] found : scala.concurrent.Future[Option[scala.concurrent.Future[F4]]]
[error] required: scala.concurrent.Future[Option[F4]]
另外,我无法访问 f1.id和f2.id :
f3 <- OptionT(api.getF3(f1.id, f2.id)
答案 0 :(得分:1)
这是cats OptionT
monad变换器的最佳选择。
你需要一些猫进口:
import cats.data.OptionT
import cats.instances.future._
让我们说这是你的数据结构(模拟):
case class F1(id: Int)
case class F2(id: Int)
case class F3(id: Int)
trait F4
object api {
def getF1(): Future[Option[F1]] = ???
def getF2(f1: Int): Future[Option[F2]] = ???
def getF3(f1: Int, f2: Int): Future[Option[F3]] = ???
def insertF(f1: Int, f2: Int, f3: Int): Future[Option[F4]] = ???
}
然后你可以这样做:
val resultT: OptionT[Future, F4] = for {
f1 <- OptionT(api.getF1())
f2 <- OptionT(api.getF2(f1.id))
f3 <- OptionT(api.getF3(f1.id, f2.id))
f4 <- OptionT(api.insertF(f1.id, f2.id, f3.id))
} yield f4
val result: Future[Option[F4]] = resultT.value
或者,您可以使用OptionT
:
type FutOpt[T] = OptionT[Future, T]
def getF1(): FutOpt[F1] = OptionT { ??? }
def getF2(f1: Int): FutOpt[F2] = OptionT { ??? }
def getF3(f1: Int, f2: Int): FutOpt[F3] = OptionT { ??? }
def insertF(f1: Int, f2: Int, f3: Int): FutOpt[F4] = OptionT { ??? }
val resultT: FutOpt[F4] = for {
f1 <- api.getF1()
f2 <- api.getF2(f1.id)
f3 <- api.getF3(f1.id, f2.id)
f4 <- api.insertF(f1.id, f2.id, f3.id)
} yield f4
val result: Future[Option[F4]] = resultT.value
您也可以使用scalaz OptionT
仅通过更改导入来保持完全相同的语法(.value
- &gt; .run
除外)。
import scalaz._
import Scalaz._
使用def insertF(f1: Int, f2: Int, f3: Int): Future[F4]
代替Future[Option[F4]]
,您可以将for-comprehension(使用scalaz
)重写为:
val resultT: OptionT[Future, F4] = for {
f1 <- OptionT(api.getF1())
f2 <- OptionT(api.getF2(f1.id))
f3 <- OptionT(api.getF3(f1.id, f2.id))
f4 <- api.insertF(f1.id, f2.id, f3.id).liftM[OptionT]
} yield f4
val result: Future[Option[F4]] = resultT.run
答案 1 :(得分:0)
val f4Response: Future[Option[Int]] = api.getF1() flatMap {
case Some(f1) => {
api.getF2(f1).flatMap {
case Some(f2) => {
api.getF3(f1.id, f2.id).flatMap {
case Some(f3) => bar(f1, f2, f3)
}
}
}
}
}
for yield
对于这种情况可能没有必要patter match
可能更好,直接没有Option.get
(可能会失败),{pattern match
更安全IUserSessionService
{1}}。