繁体   English   中英

Scala对未来和选项的理解

[英]Scala for comprehension with future and options

object Main extends App {
  val p1 = Promise[Option[String]]()
  val p2 = Promise[Option[String]]()
  val f1 = p1.future
  val f2 = p2.future

  val res = (for{
    file1Opt <- f1
    file2Opt <- f2
    file1 <- file1Opt
    file2 <- file2Opt
  } yield {
    combineFiles(file1, file2)
  }).fallbackTo(Future.successful("Files not found"))

  Thread.sleep(2000)
  println("XXXXXXXXXXXXXXXXXXX")

  p1.success(Some("file one"))
  p2.success(Some("file two"))

  val finalData = res.map(s =>
    s + " " + "add more data to the file"
  ) 

  finalData.map(println(_))

  def combineFiles(f1: String, f2: String): String = {
    f1 + " " + f2
  }
}

我有两个函数返回Future[Option[String]] ,我需要将两个字符串组合成一个字符串。

我希望输出是两个字符串和页脚的组合:“文件一个文件两个向文件添加更多数据”或默认当一个或两个Future返回None :“找不到文件将更多数据添加到文件”。

怎么能实现这一目标?

编译错误:

Error:(16, 11) type mismatch;
found   : Option[String]
required: scala.concurrent.Future[?]
file1 <- file1Opt
      ^ 

好吧,如果不做像monad变形金刚或其他东西那样的任何东西,人们可以简单地for理解而筑巢。 它将更加冗长,但没有额外的依赖。

val res = (for{ 
  file1Opt <- f1
  file2Opt <- f2
} yield for {
  file1 <- file1Opt
  file2 <- file2Opt
} yield combineFiles(file1, file2))
.fallbackTo(Future.successful(Some("Files not found")))
//or, alternatively, .fallbackTo(Future.successful(None))

最终,问题在于您尝试将FutureOption组合在一起for理解。 由于其他受访者提到的原因,这不起作用。 但是,嵌套工作得很好。

嵌套的缺点是最终会出现非常复杂的数据结构,这可能不容易在程序的其他地方使用。 你应该考虑如何压扁它们,即从Future[Option[String]]Future[String] 你的具体情况是这样的: res.map(_.getOrElse(""))

好吧,可能有两个级别的嵌套很好,但是你嵌套的比较多,考虑在让同事处理它之前弄平该层次结构。 :)

ALF在他的回答中提到,您可以使用单子发电产品对于这一点,在这种情况下OptionT

使用猫的一个例子:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.data.OptionT
import cats.implicits._

val file1: Future[Option[String]] = Future.successful(Some("file1"))
val file2: Future[Option[String]] = Future.successful(Some("file2"))

val combinedOT: OptionT[Future, String] =
  for {
    f1 <- OptionT(file1)
    f2 <- OptionT(file2)
  } yield s"$f1 $f2"

val combinedFO: Future[Option[String]] = combinedOT.value
val combinedF: Future[String] = combinedOT.getOrElse("Files not found")

请注意,如果你使用的猫,可以更换为理解combinedOT2用笛卡尔生成器(该|@| ),因为file2不依赖于file1

val combinedOT2: Future[Option[String]] = 
  (OptionT(file1) |@| OptionT(file2)).map(_ + " " + _).value

如果“组合”的Future失败,你仍然可以使用fallbackTo ,尽管使用recoverrecoverWith来实际检查你想从哪个Throwable recover可能更好。

我认为这个问题在这篇47deg博文中以及在这篇 文章中都有所涉及: monads不构成,所以你需要从一个monad到另一个monad的变换器,因为没有flatMap操作可以(平面)将Future映射到Option

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM