我正在尝试将 Try
与 Future
s混合在Scala的 for
循环中,而没有使用 Future.fromTry
明确地将 Try
转换为 Future
. 看起来它在某些情况下会自动运行,但在其他情况下则不然 .
以下代码段失败了
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util._
for {
a <- Try(5)
b <- Future(10)
} yield { a + b }
类型不匹配; found:scala.concurrent.Future [Int] required:scala.util.Try [?] b < - Future {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中的行为相同 .
1 回答
foreach
返回Unit
类型;因此"common"类型 .如果没有
yield
关键字,编译器会将您的for-comprehension解释为:你可以处理
Future
和Try
(两个不同的monad),只要你将它们链接在foreach
周围 .如果添加
yield
关键字,编译器将使用flatMap
/map
解释您的for-understandnce;如下:Try#flatMap
期望一个函数具有Try
作为返回类型,但它得到一个Future
,使整个不编译 .TL;DR: foreach does not expect matching of function types during chaining since it returns Unit in all cases; that's why it compiles.
请注意以下内容:
因为
map
不需要压扁类型;所以用不同的"effects"包装编译 . 扁平化不同类型会使编译器失败;正如flatMap
试图做的那样 .