在 Scala 2.13 中,为什么伴随对象的隐式作用域有时可能会错位?如何纠正?

tri*_*oid 0 scala implicit typeclass companion-object

下面是一个测试 scala 2.13 编译器隐式特性的简单示例:

object OverridingScope {

  trait System {

    trait Handler[T]
  }

  object Sys1 extends System {

    object Handler {

      implicit def handle1: Handler[Int] = new Handler[Int] {}
    }

    implicit def handle2: Handler[Long] = new Handler[Long] {}
  }
}
Run Code Online (Sandbox Code Playgroud)

根据这篇文章:

Scala 在哪里寻找隐式?

Handler当使用 type 时,trait 的伴生对象可以作为隐式作用域的一部分自动导入Handler[_],外部对象Sys1应该是无关紧要的。这意味着 handle1 应该是可见的,而 handle2 应该是隐藏的。

但是下面的测试用例显示了完全相反的情况:

class OverridingScope extends BaseSpec {

  import OverridingScope._

  it("implicits in companion is in scope") {

//    val hh = implicitly[Sys1.Handler[Int]]
    // Doesn't work
  }

  it("implicits in outer object is in scope") {

    val hh = implicitly[Sys1.Handler[Long]]
    // Should NOT work
  }
}
Run Code Online (Sandbox Code Playgroud)

考虑到 Handler 既是类名又是对象名,handle1 不起作用的事实看起来非常可疑。另外,我检查了隐式导入的完整列表:

First look in current scope
Implicits defined in current scope
Explicit imports
wildcard imports
Same scope in other files
Now look at associated types in
Companion objects of a type
Implicit scope of an argument's type (2.9.1)
Implicit scope of type arguments (2.8.0)
Outer objects for nested types
Other dimensions
Run Code Online (Sandbox Code Playgroud)

以上都不能解释为什么 handle2 在范围内。可能是什么原因?

顺便说一句:对于那些认为隐式是一个重要的 Scala 特性的人:隐式是实现类型类的唯一方法,如果你想用最少的样板来实现它,有时上面的模式可能是唯一的选择。

Jas*_*r-M 5

这里的第 3 点解释了所讨论类型的前缀中的隐式/给定有助于其隐式范围(在 Scala 3 中不是如果它是一个包)。所以对于类型Sys1.Handler[Long]隐含在Sys1隐式范围内,因为Sys1是一个非包前缀。

handle1不在隐式范围内,因为 objectHandler中的 objectSys1不是 traitHandler中 trait的伴生对象System

  • 是的,但唯一应该不同的是 Scala 3 中前缀不能是包的规则。 (4认同)