我正在阅读Scala Cookbook(http://shop.oreilly.com/product/0636920026914.do)
有一个与未来使用有关的例子涉及到理解。
到目前为止,我对理解的理解是,当与集合一起使用时,它将产生具有相同类型的另一个集合。例如,如果每个futureX
的类型为Future[Int]
,则以下内容也应为Future[Int]
类型:
for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
有人可以解释一下在此代码中使用<-
时究竟发生了什么吗?
我知道如果它是一个生成器,它将通过循环来获取每个元素。
答案 0 :(得分:123)
首先要理解。它在很多时候得到了回答,它是对几个monadic操作的抽象:map
,flatMap
,withFilter
。当您使用<-
时,scalac将这些行去掉为monadic flatMap
:
r <- monad
加入monad.flatMap(r => ... )
它看起来像一个命令式计算(monad是什么),你将计算结果绑定到r
。 yield
部分被map
调用。结果类型取决于monad
的类型。
Future
特质具有flatMap
和map
个函数,因此我们可以使用它来理解它。在您的示例中可以将以下代码解压缩:
future1.flatMap(r1 => future2.flatMap(r2 => future3.map(r3 => r1 + r2 + r3) ) )
不言而喻,如果future2
的执行取决于r1
,则无法逃避顺序执行,但如果将来的计算是独立的,则有两种选择。您可以强制执行顺序执行,也可以允许执行并行执行。您不能强制执行后者,因为执行上下文将处理此问题。
val res = for {
r1 <- computationReturningFuture1(...)
r2 <- computationReturningFuture2(...)
r3 <- computationReturningFuture3(...)
} yield (r1+r2+r3)
将始终按顺序运行。它可以通过desugaring轻松解释,之后后续的computationReturningFutureX
调用仅在flatMaps中调用,即
computationReturningFuture1(...).flatMap(r1 =>
computationReturningFuture2(...).flatMap(r2 =>
computationReturningFuture3(...).map(r3 => r1 + r2 + r3) ) )
然而,这可以并行运行,并且for comprehension聚合结果:
val future1 = computationReturningFuture1(...)
val future2 = computationReturningFuture2(...)
val future3 = computationReturningFuture3(...)
val res = for {
r1 <- future1
r2 <- future2
r3 <- future3
} yield (r1+r2+r3)
答案 1 :(得分:0)
在这里详细说明现有答案,这是一个简单的结果,用于说明for
理解是如何运作的。
它有点冗长的功能,但值得深入研究。
一个为我们提供一系列整数的函数
scala> def createIntegers = Future{
println("INT "+ Thread.currentThread().getName+" Begin.")
val returnValue = List.range(1, 256)
println("INT "+ Thread.currentThread().getName+" End.")
returnValue
}
createIntegers: createIntegers: scala.concurrent.Future[List[Int]]
为我们提供一系列字符的函数
scala> def createAsciiChars = Future{
println("CHAR "+ Thread.currentThread().getName+" Begin.")
val returnValue = new ListBuffer[Char]
for (i <- 1 to 256){
returnValue += i.toChar
}
println("CHAR "+ Thread.currentThread().getName+" End.")
returnValue
}
createAsciiChars: scala.concurrent.Future[scala.collection.mutable.ListBuffer[Char]]
使用这些函数调用中的进行理解。
scala> val result = for{
i <- createIntegers
s <- createAsciiChars
} yield i.zip(s)
Await.result(result, Duration.Inf)
result: scala.concurrent.Future[List[(Int, Char)]] = Future(<not completed>)
对于以下这些行,我们可以看出所有函数调用都是同步的,即createAsciiChars
函数调用未执行,直到createIntegers
完成执行。
scala> INT scala-execution-context-global-27 Begin.
INT scala-execution-context-global-27 End.
CHAR scala-execution-context-global-28 Begin.
CHAR scala-execution-context-global-28 End.
在createAsciiChars
理解之外进行这些函数createIntegers
,for
调用将是异步执行。
答案 2 :(得分:-1)
如果可能,它允许r1
,r2
,r3
并行运行。这可能是不可能的,这取决于有多少线程可用于执行Future计算,但是通过使用这种语法,您告诉编译器如果可能的话并行运行这些计算,然后在完成所有计算后执行yield()