我在Scala中发现myselfe的常见情况如下:
Option
Future
Option
这会产生Option[Future[Option[_]]]
这样的类型,更好的解决方案是使用Future[Option[Option[_]]]
之类的转换,例如使用下面的内容:
def transform[A](o: Option[Future[A]]): Future[Option[A]] =
o.map(f => f.map(Option(_))).getOrElse(Future.successful(None))
(代码从here被盗)
然后,我可以使用Options
在Future
内使用任意数量的flatmap
。
这似乎是一种常见的模式,我确信它可以在某种意识形态的方式中在Scala中使用,而不必一遍又一遍地实现变换方法。
所以我的问题是:如上例所示,将Option[Future[Option[_]]]
改为外部的最理想方式是什么?
答案 0 :(得分:1)
cat库中的Traverse
类型类可能对此有所帮助。它可以处理将Option[Future[Something]]
转换为Future[Option[Something]]
。
使用Ammonite REPL的例子:
$ amm
Loading...
Welcome to the Ammonite Repl 0.7.7
(Scala 2.11.8 Java 1.8.0_101)
@ import $ivy.`org.typelevel::cats-core:0.7.2`
import $ivy.$
首先是一些进口......
@ import cats.Traverse
import cats.Traverse
@ import cats.implicits._
import cats.implicits._
@ import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
@ import scala.concurrent.Future
import scala.concurrent.Future
这是我们想要改变的事情:
@ val optionOfFuture: Option[Future[String]] = Some(Future.successful("hello"))
optionOfFuture: Option[Future[String]] = Some(scala.concurrent.impl.Promise$KeptPromise@43ac3b45)
我们使用Traverse
的{{1}}方法切换sequence
和Option
:
Future
或者如果您更喜欢语法加糖版本:
@ val futureOfOption: Future[Option[String]] = Traverse[Option].sequence(optionOfFuture)
futureOfOption: Future[Option[String]] = Success(Some(hello))
有关@ import cats.syntax.traverse._
import cats.syntax.traverse._
@ val futureOfOption2: Future[Option[String]] = optionOfFuture.sequence
futureOfOption2: Future[Option[String]] = Success(Some(hello))
可以执行的操作的更多信息,请查看cats documentation。
答案 1 :(得分:1)
我认为,问题在于你的问题是#3:为什么"结果的某些转换",操纵Future
会返回Option
?闻起来有点不对劲。只是让他们首先返回Future
,你就不会遇到这个问题。
顺便说一句,我不确定你的意思是什么"能够使用flatMap"来处理任意数量的选项,但几乎肯定是错的:flatMap
将帮助您在地图时删除 1 额外级别的选项:Some(Some("foo")).flatMap(x => Some(s))
会产生Some(Some("foo"))
。 .flatten
明确地做了同样的事情:
Some(Some(Some("foo"))).flatten
会产生Some(Some("foo"))
,而不是Some("foo")
或"foo"
,正如您所期望的那样。
请注意,在每种情况下,只有一个级别的选项,展平处理,而不是"任意数字"。
通常的做法是在遇到它们时摆脱额外的选项(立即变平以永远拥有Future[Option[T]]
而不是Future[Option[Option[T]]]
)。
答案 2 :(得分:0)
val a: Option[Future[Option[T]]] = ...
val b: Future[Option[T]] = a.getOrElse(Future(None))