Scala从Try到Future的隐式转换

时间:2018-04-15 13:56:06

标签: scala for-loop future implicit-conversion implicit

我正在尝试将TryFuture 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循环重写为嵌套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中的行为相同。

1 个答案:

答案 0 :(得分:3)

foreach返回Unit类型;因此,&#34;普通&#34;类型。

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

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

只要您将Future链接起来,就可以处理Tryforeach(两个不同的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所做的那样。