Scala Option[Future[T]] 到 Future[Option[T]]

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38226203/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 08:26:54  来源:igfitidea点击:

Scala Option[Future[T]] to Future[Option[T]]

scalafuture

提问by Micha? Jurczuk

How can I convert Option[Future[T]]to Future[Option[T]]in scala?

如何转换Option[Future[T]]Future[Option[T]]Scala ?

I want to use it in:

我想在以下方面使用它:

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

Here signature insert method

这里签名插入方法

def insert(address: Address): Future[Address]

cais a CustomerData

ca是客户数据

case class CustomerData(address: Address, invoiceAddress: Option[Address])

回答by Kevin Meredith

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)
  }

Examples:

例子:

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

回答by RawToast

The standard library does provide the methods to use Future.sequence on an Option, unfortunately you have to plumb them together.

标准库确实提供了在 Option 上使用 Future.sequence 的方法,不幸的是您必须将它们连接在一起。

Either as a quick method:

作为一种快速方法:

def swap[M](x: Option[Future[M]]): Future[Option[M]] =
    Future.sequence(Option.option2Iterable(x)).map(_.headOption)

Note I found the implicit Option.option2Iterablewas already in scope for me. So you may not need to provide it, reducing the code down to Future.sequence(x).map(_.headOption)

注意我发现隐式Option.option2Iterable已经在我的范围内。所以你可能不需要提供它,将代码减少到Future.sequence(x).map(_.headOption)

Or you may prefer an extension method:

或者您可能更喜欢扩展方法:

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

回答by gun

If you have cats as a dependency in your application, the most beautiful way would be to use traverse

如果您的应用程序中有猫作为依赖项,那么最好的方法是使用 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)

回答by Yaroslav

Here is another solution:

这是另一个解决方案:

def swap[T](o: Option[Future[T]]): Future[Option[T]] =
  o.map(_.map(Some(_))).getOrElse(Future.successful(None))

The trick is to convert Option[Future[T]]into Option[Future[Option[T]]]which is easy, and then extract the value from that Option.

诀窍是转换Option[Future[T]]Option[Future[Option[T]]]which 很容易,然后从中提取值Option

回答by Guillem I

When you have a list (or any TraversableOnce) of futures and want a single future for computing the whole list, you use Future.sequenceor Future.traverse. You can think of an Option like a list of 1 or 0 elements but since is technically not a list you have to go for a little conversion in this case. Anyway, this is a code that does it normally:

当您有一个TraversableOnce期货列表(或任何)并且想要一个单一的期货来计算整个列表时,您可以使用Future.sequenceFuture.traverse。您可以将 Option 视为 1 或 0 个元素的列表,但由于技术上不是列表,因此在这种情况下您必须进行一些转换。无论如何,这是一个正常执行的代码:

  val optionFuture:Option[Future[String]] = ???

  val futureOption:Future[Option[String]] = Future.sequence(optionFuture.toIterable).map(_.headOption)

In you example use better Future.traverse:

在你的例子中使用更好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

回答by Shantiswarup Tunga

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)