【问题标题】:Type Mismatch on Scala For Comprehension: scala.concurrent.FutureScala上的类型不匹配以供理解:scala.concurrent.Future
【发布时间】:2023-11-25 04:57:01
【问题描述】:

我对 Scala 还很陌生,请多多包涵。我有一堆包裹在一个大数组中的期货。 Futures 已经完成了他们的辛勤工作,查看了几 TB 的数据,在我的应用程序结束时,我想总结上述 futures 的所有结果,以便我可以很好地展示它们。

我拥有的期货集合属于以下类型:

Array[Future[List(String, String, String)]]

到目前为止,我所读到的所有关于理解的内容都表明

val test: Seq[Seq[List[String]]] = Seq(Seq(List("Hello", "World"), List("What's", "Up")))

val results = for {
  test1 <- test
  test2 <- test1
  test3 <- test2
} yield test3

结果

results: Seq[String] = List(Hello, World, What's, Up)

按照同样的逻辑,我的意图是这样做,因为我最近发现 Option、Try、Failure 和 Success 可以被视为集合:

val futures = { ... } // Logic that collects my Futures

// futures is now Array[Future[List(String, String, String)]]

val results = for {
  // futureSeq as Seq[List(String, String, String]
  futureSeq <- Future.sequence(futures.toSeq)
  // resultSet as List(String, String, String)
  resultSet <- futureSeq
} yield resultset

但这不起作用。我似乎收到以下编译错误:

错误:(78, 15) 类型不匹配;
找到:Seq[List(String, String, String)]
必需:scala.concurrent.Future[?]

结果集

需要的部分: scala.concurrent.Future[?] 完全让我失望。我完全不明白为什么那里需要 Future。

我已经通过 REPL、调试和使用 IntelliJ 的类型检查检查了所有对象的类型。他们似乎证实了我不只是对自己的类型感到困惑。

在任何人提到之前,是的,我知道 for-comprehension 是一堆地图、flatMaps 和 withFilters 的语法糖。

【问题讨论】:

  • 根据scala-lang.org/api/2.11.7/#scala.concurrent.Future$,Future.sequence "Transforms a TraversableOnce[Future[A]] into a Future[TraversableOnce[A]]" 所以 Future.sequence(futures.toSeq) 是形式 Future.sequence(Seq[Future[List(String, String, String)]]) 将 Seq[Future[List(String, String, String)]] 转换为 Future[Seq[List(String, String, String)] ].
  • @Tris:这不能证实我的意思吗? futureSeq
  • 我是说它朝相反的方向发展,并导致一个 Future[Seq[List(String, String, String)]] 不可遍历。我可以使用一个最小的完整示例来演示该问题,但是我怀疑可行的是 seqFuture 的结果集
  • @Tris:感谢您指出这一点。我盯着这个东西看了好几个小时,我什至没有看到我在做 Future.sequence(futures.toSeq) 而不是 futures.toSeq。它仍然不允许我做 resultSet
  • 那是因为遍历 Seq[Future[List(String, String, String)]] 中的 Seq 会留下 Future[List(String, String, String)] 从中提取和遍历 List(String , String, String) 这需要完成可以用 Future.result(atMost: Duration) 完成的 Future。基于所有这些可以做到:futureFromSeq

标签: scala future type-mismatch


【解决方案1】:

for-comprehension 如何取消对flatMapmap 的调用的详细信息在这里很重要。这段代码:

for {
  futureSeq <- Future.sequence(futures.toSeq)
  resultSet <- futureSeq
} yield resultset

或多或少会变成这样:

Future.sequence(futures.toSeq).flatMap(futureSeq => futureSeq)

Future 上的 flatMap 需要一个返回 Future 的函数,但您已经给它一个返回 Seq[List[(String, String, String)]] 的函数。

一般情况下,您不能在for-comprehensions 中混合类型(序列理解中的Option 是一种隐式转换支持的异常)。如果您有一个来自未来的&lt;- 箭头,那么您所有其余的&lt;- 箭头都需要来自未来。

你可能想要这样的东西:

val results: Future[Seq[(String, String, String)]] =
  Future.sequence(futures.toSeq).map(_.flatten)

然后你可以使用这样的东西:

import scala.concurrent.Await
import scala.concurrent.duration._

Await.result(results.map(_.map(doSomethingWithResult)), 2.seconds)

同步呈现结果(阻塞直到完成)。

【讨论】:

    最近更新 更多