我正在尝试将Try
与Future
s混合在Scala的for
循环中,而不是将Try
显式转换为Future
s与Future.fromTry
。看起来它在某些情况下会自动运行,但在其他情况下则不然。
以下代码段失败
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util._
for {
a <- Try(5)
b <- Future(10)
} yield { a + b }
类型不匹配;
发现:scala.concurrent.Future [Int]
必需:scala.util.Try [?]
b&lt; - 未来{10}
^
编译失败
另一方面,如果我删除关键字yield
,则可以使用:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util._
for {
a <- Try(5)
b <- Future(10)
} { println(a + b) }
当我将for
循环重写为嵌套foreach
或map
时,它也有效:
@ Try(5) foreach { a => Future(10) foreach { b => println(a + b) } }
15
@ Try(5) map { a => Future(10) map { b => a + b } }
res5: Try[Future[Int]] = Success(Future(Success(15)))
有人可以解释我为什么会这样吗?这是一个错误吗?或者我错过了什么?
PS。它与Scala 2.11和2.12中的行为相同。
答案 0 :(得分:3)
foreach
返回Unit
类型;因此,&#34;普通&#34;类型。
如果没有yield
关键字,编译器会将您的for-comprehension解释为:
Try(5).foreach(a => Future(10).foreach(b => println(a + b)))
只要您将Future
链接起来,就可以处理Try
和foreach
(两个不同的monad)。
如果您添加yield
关键字,编译器会使用flatMap
/ map
来解释您的理解;如下:
Try(5).flatMap(a => Future(10).map(b => a + b))
Try#flatMap
期望一个函数具有Try
作为返回类型,但它得到一个Future
,使整个不编译。
TL; DR:foreach
不期望在链接期间匹配函数类型,因为它在所有情况下都返回Unit;这就是它编译的原因。
请注意以下内容:
Try(5) map { a => Future(10) map { b => a + b } }
起作用,因为map
不需要展平类型;所以包装编译具有不同的&#34;效果&#34;。
扁平化不同类型会使编译器失败;正如flatMap
所做的那样。