我试图在 Scala 的 for
循环中将 Try
与 Future
混合,而不显式转换 Try
s 到 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 }
type mismatch;
found : scala.concurrent.Future[Int]
required: scala.util.Try[?]
b <- Future { 10 }
^
Compilation Failed
另一方面,如果我删除关键字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 中的行为相同。
最佳答案
foreach
返回一个 Unit
类型;因此是“常见”类型。
如果没有 yield
关键字,编译器会将您的 for 理解解释为:
Try(5).foreach(a => Future(10).foreach(b => println(a + b)))
只要将 Future
和 Try
(两个不同的 monad)链接到 foreach
周围,就可以处理它们。
如果您添加 yield
关键字,编译器将使用 flatMap
/map
解释您的 for 理解;如下:
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
不需要展平类型;所以包装编译具有独特的“效果”。
展平不同的类型会使编译器失败;正如 flatMap
尝试做的那样。
关于Scala 从 Try 到 Future 的隐式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49842751/