Scala Option[Future[T]] 到 Future[Option[T]]
Scala Option[Future[T]] to Future[Option[T]]
如何在 Scala 中将 Option[Future[T]]
转换为 Future[Option[T]]
?
我想用在:
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- ca.invoiceAddress.map(addressDAO.insert) // Option[Future[Address]]
} yield (a, ia) // Invalid value have to be two futures
此处签名插入方式
def insert(address: Address): Future[Address]
ca
是一个客户数据
case class CustomerData(address: Address, invoiceAddress: Option[Address])
import scala.concurrent.Future
import scala.concurrent.ExecutionContext
def f[A](x: Option[Future[A]])(implicit ec: ExecutionContext): Future[Option[A]] =
x match {
case Some(f) => f.map(Some(_))
case None => Future.successful(None)
}
示例:
scala> f[Int](Some(Future.successful(42)))
res3: scala.concurrent.Future[Option[Int]] = Success(Some(42))
scala> f[Int](None)
res4: scala.concurrent.Future[Option[Int]] = scala.concurrent.impl.Promise$KeptPromise@c88a337
标准库确实提供了在选项上使用 Future.sequence 的方法,不幸的是,您必须将它们结合在一起。
作为快速方法:
def swap[M](x: Option[Future[M]]): Future[Option[M]] =
Future.sequence(Option.option2Iterable(x)).map(_.headOption)
注意我发现隐式 Option.option2Iterable
已经在我的范围内。所以你可能不需要提供它,将代码减少到 Future.sequence(x).map(_.headOption)
或者您可能更喜欢扩展方法:
implicit class OptionSwitch[A](f: Option[Future[A]]) {
import scala.concurrent.Future
def switch: Future[Option[A]] = Future.sequence(Option.option2Iterable(f))
.map(_.headOption)
}
val myOpt = Option(Future(3))
myOpt.switch
这是另一个解决方案:
def swap[T](o: Option[Future[T]]): Future[Option[T]] =
o.map(_.map(Some(_))).getOrElse(Future.successful(None))
诀窍是将 Option[Future[T]]
转换为 Option[Future[Option[T]]]
这很容易,然后从 Option
.
中提取值
如果你的应用程序中有猫作为依赖项,最漂亮的方法是使用 traverse
import cats._
import cats.implicits._
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- ca.invoiceAddress.traverse(addressDAO.insert) // Future[Option[Address]]
} yield (a, ia)
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- ca.invoiceAddress.map(x => addressDAO.insert(x).map(_.map(k => Some(k))).getOrElse(Future.successful(None)))
} yield (a, ia)
当您有一个期货列表(或任何 TraversableOnce
)并且想要一个单一的期货来计算整个列表时,您可以使用 Future.sequence
或 Future.traverse
。您可以将 Option 想象成 1 个或 0 个元素的列表,但由于从技术上讲它不是一个列表,因此在这种情况下您必须进行一些转换。无论如何,这是正常执行的代码:
val optionFuture:Option[Future[String]] = ???
val futureOption:Future[Option[String]] = Future.sequence(optionFuture.toIterable).map(_.headOption)
在你的例子中使用更好Future.traverse
:
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- Future.traverse(ca.invoiceAddress.toIterable)(addressDAO.insert).map(_.headOption) // Future[Option[Address]]
} yield CustomerData(a, ia) // Types OK
您可以简单地使用 Dumonad
import io.github.dumonad.dumonad.Implicits._
futureOfOption.dummed
如何在 Scala 中将 Option[Future[T]]
转换为 Future[Option[T]]
?
我想用在:
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- ca.invoiceAddress.map(addressDAO.insert) // Option[Future[Address]]
} yield (a, ia) // Invalid value have to be two futures
此处签名插入方式
def insert(address: Address): Future[Address]
ca
是一个客户数据
case class CustomerData(address: Address, invoiceAddress: Option[Address])
import scala.concurrent.Future
import scala.concurrent.ExecutionContext
def f[A](x: Option[Future[A]])(implicit ec: ExecutionContext): Future[Option[A]] =
x match {
case Some(f) => f.map(Some(_))
case None => Future.successful(None)
}
示例:
scala> f[Int](Some(Future.successful(42)))
res3: scala.concurrent.Future[Option[Int]] = Success(Some(42))
scala> f[Int](None)
res4: scala.concurrent.Future[Option[Int]] = scala.concurrent.impl.Promise$KeptPromise@c88a337
标准库确实提供了在选项上使用 Future.sequence 的方法,不幸的是,您必须将它们结合在一起。
作为快速方法:
def swap[M](x: Option[Future[M]]): Future[Option[M]] =
Future.sequence(Option.option2Iterable(x)).map(_.headOption)
注意我发现隐式 Option.option2Iterable
已经在我的范围内。所以你可能不需要提供它,将代码减少到 Future.sequence(x).map(_.headOption)
或者您可能更喜欢扩展方法:
implicit class OptionSwitch[A](f: Option[Future[A]]) {
import scala.concurrent.Future
def switch: Future[Option[A]] = Future.sequence(Option.option2Iterable(f))
.map(_.headOption)
}
val myOpt = Option(Future(3))
myOpt.switch
这是另一个解决方案:
def swap[T](o: Option[Future[T]]): Future[Option[T]] =
o.map(_.map(Some(_))).getOrElse(Future.successful(None))
诀窍是将 Option[Future[T]]
转换为 Option[Future[Option[T]]]
这很容易,然后从 Option
.
如果你的应用程序中有猫作为依赖项,最漂亮的方法是使用 traverse
import cats._
import cats.implicits._
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- ca.invoiceAddress.traverse(addressDAO.insert) // Future[Option[Address]]
} yield (a, ia)
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- ca.invoiceAddress.map(x => addressDAO.insert(x).map(_.map(k => Some(k))).getOrElse(Future.successful(None)))
} yield (a, ia)
当您有一个期货列表(或任何 TraversableOnce
)并且想要一个单一的期货来计算整个列表时,您可以使用 Future.sequence
或 Future.traverse
。您可以将 Option 想象成 1 个或 0 个元素的列表,但由于从技术上讲它不是一个列表,因此在这种情况下您必须进行一些转换。无论如何,这是正常执行的代码:
val optionFuture:Option[Future[String]] = ???
val futureOption:Future[Option[String]] = Future.sequence(optionFuture.toIterable).map(_.headOption)
在你的例子中使用更好Future.traverse
:
val customerAddresses = for {
a <- addressDAO.insert(ca.address) // Future[Address]
ia <- Future.traverse(ca.invoiceAddress.toIterable)(addressDAO.insert).map(_.headOption) // Future[Option[Address]]
} yield CustomerData(a, ia) // Types OK
您可以简单地使用 Dumonad
import io.github.dumonad.dumonad.Implicits._
futureOfOption.dummed