我有以下未来:
Right-click the sheet's Tab, click "Unprotect Sheet..."
Enter your password and click OK
我需要以下代码才能返回def f1 = Future {1}
def f2 = Future {2}
:
Future[(Int,Int)]
而不是val future = // function that returns a future
future.flatMap {
val x1 = f1
val x2 = f2
(x1,x2) // This returns Future[Int],Future[Int]
}
我需要函数返回(Future[Int],Future[Int])
。如何转换呢?
答案 0 :(得分:2)
这是一个理解的经典用例。
for {
x1 <- f1
x2 <- f2
} yield (x1, x2)
这相当于flatmap后跟地图
f1.flatMap(x1 => f2.map(x2 => (x1,x2)))
由于在x1准备好之前你不会到达f1.flatMap的内部,所以这段代码将按顺序执行。
如果您希望期货同时执行,您可以在理解之前实例化期货。
val future1 = f1
val future2 = f2
for {
x1 <- future1
x2 <- future2
} yield (x1, x2)
答案 1 :(得分:2)
我将在这里接受(目前)接受的答案。根据我的评论,这并不是正确的方式将压缩两种方式放在一起。正确的方法就是:
f1 zip f2
另一个答案:
for (x <- f1; y <- f2) yield (x, y)
虽然这会起作用,但在f2
是一个产生未来的表达式(就像在这个问题中一样)的情况下,它并不平行。如果是这种情况,则在第一个未来完成 [1] 之前,不会构建f2
。虽然zip
以flatMap
的方式以同样的方式实现,但因为它的参数是严格的,所以第二个未来已经在运行(当然,这取决于执行上下文)。
它也更简洁!
[1] - 可以通过观察y
(由f1
计算的值)在范围内构建f2
来看出这一点
这很容易证明:
scala> import scala.concurrent._; import ExecutionContext.Implicits.global
import scala.concurrent._
import ExecutionContext.Implicits.global
scala> def createAndStartFuture(i: Int): Future[Int] = Future {
| println(s"starting $i in ${Thread.currentThread.getName} at ${java.time.Instant.now()}")
| Thread.sleep(20000L)
| i
| }
createAndStartFuture: (i: Int)scala.concurrent.Future[Int]
有了这个:
scala> for (x <- createAndStartFuture(1); y <- createAndStartFuture(2)) yield (x, y)
starting 1 in scala-execution-context-global-34 at 2017-05-05T10:29:47.635Z
res15: scala.concurrent.Future[(Int, Int)] = Future(<not completed>)
// Waits 20s
starting 2 in scala-execution-context-global-32 at 2017-05-05T10:30:07.636Z
但是有拉链
scala> createAndStartFuture(1) zip createAndStartFuture(2)
starting 1 in scala-execution-context-global-34 at 2017-05-05T10:30:45.434Z
starting 2 in scala-execution-context-global-32 at 2017-05-05T10:30:45.434Z
res16: scala.concurrent.Future[(Int, Int)] = Future(<not completed>)