从 Try 到 Future 的 Scala 隐式转换

Scala implicit conversion from Try to Future

我试图在 Scala 的 for 循环中将 Trys 与 Futures 混合,而不显式地将 Trys 转换为 Futures 与 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 循环重写为嵌套的 foreachmap:

时它也有效
@ 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 return是Unit类型;因此是 "common" 类型。

没有 yield 关键字,编译器将您的 for-comprehension 解释为:

Try(5).foreach(a => Future(10).foreach(b => println(a + b)))

您可以处理 FutureTry(两个不同的单子),只要您将它们链接在 foreach.

周围

如果你加yield关键字,编译器会用flatMap/map解释你的for-comprehension;如下:

Try(5).flatMap(a => Future(10).map(b => a + b))

Try#flatMap 需要一个 Try 作为 return 类型的函数,但它得到了 Future,使得整个函数无法编译。

TL;DR:foreach 不期望在链接期间匹配函数类型,因为它在所有情况下都是 returns Unit;这就是它编译的原因。

注意以下几点:

Try(5) map { a => Future(10) map { b => a + b } }

有效,因为 map 不需要展平类型;所以包装编译时使用不同的 "effects"。 扁平化不同的类型会使编译器失败;正如 flatMap 尝试做的那样。