Scala 2.12中的隐式ExecutionContext优先级

7

在Scala 2.12中,导入global执行上下文并在作用域中定义另一个隐式执行上下文将导致模棱两可的隐式情况,而在2.11中则完全正常。

import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global

class A(implicit ec: ExecutionContext) {
  x = implicitly[ExecutionContext]
}

编译器出现错误:
error: ambiguous implicit values:
 both lazy value global in object Implicits of type => scala.concurrent.ExecutionContext
 and value ec in class A of type scala.concurrent.ExecutionContext
 match expected type scala.concurrent.ExecutionContext
       val x = implicitly[ExecutionContext]
                         ^

这是什么原因,如何在代码中解决?

1
相关的Scala/Scala存储库中的提交是https://github.com/scala/scala/commit/44953dcb08fc5dd92e423a56bd42bcc32757aaef,更改的理由是https://issues.scala-lang.org/browse/SI-8849。 - Seth Tisue
Viktor Klang在JIRA工单上的评论:“建议明确传递ExecutionContext.global,或者在需要时引入自己的指向它的implicit val。” - Seth Tisue
如果我理解问题正确,在2.11中它实际上是“错误”的,或者至少是出乎意料的,因为“全局”被选择而不是作用域中的隐式变量?而2.12通过使其模糊不清来暴露这个潜在的编程错误。值得在发布说明和/或文档中提到。 - ochrons
Viktor Klang 在 Gitter 上说:“在 < 2.12 版本中,全局与用户提供的 EC 的隐式解析令人惊讶。因此,任何冲突现在都表明您存在错误。”(https://gitter.im/scala/scala?at=5822218431c5cbef43d051d8) - Seth Tisue
1个回答

2
规范将重载决策视为选择类成员的消歧义。但是,隐式解析使用静态重载决策来在非成员引用之间进行选择。
可以认为以下内容是对规范的错误解释,因为zzzyyy一样,在派生自X的类中定义:
$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_101).
Type in expressions for evaluation. Or try :help.

scala> import concurrent._, ExecutionContext.global
import concurrent._
import ExecutionContext.global

scala> trait X { implicit val xxx: ExecutionContext = global }
defined trait X

scala> class Y extends X { implicit val yyy: ExecutionContext = global ; def f = implicitly[ExecutionContext] }
defined class Y

scala> class Z extends X { def f(implicit zzz: ExecutionContext) = implicitly[ExecutionContext] }
<console>:16: error: ambiguous implicit values:
 both value xxx in trait X of type => scala.concurrent.ExecutionContext
 and value zzz of type scala.concurrent.ExecutionContext
 match expected type scala.concurrent.ExecutionContext
       class Z extends X { def f(implicit zzz: ExecutionContext) = implicitly[ExecutionContext] }
                                                                             ^

目前,您必须依靠命名来遮蔽来自封闭作用域的隐式内容:

scala> class Z extends X { def f(implicit xxx: ExecutionContext) = implicitly[ExecutionContext] }
defined class Z

或者,

scala> :pa
// Entering paste mode (ctrl-D to finish)

package object p { import concurrent._ ; implicit val xxx: ExecutionContext = ExecutionContext.global }
package p { import concurrent._ ;
  class P { def f(implicit xxx: ExecutionContext) = implicitly[ExecutionContext]
            def g = implicitly[ExecutionContext] }
}

// Exiting paste mode, now interpreting.


scala> 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接