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

下面是一个测试 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] {}
  }
}

根据这篇文章:

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
  }
}

考虑到 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

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

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

回答

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

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

  • Yes but the only thing that should be different is the rule that the prefix can't be a package in Scala 3.

以上是在Scala2.13中,为什么伴随对象的隐式作用域有时可能会错位?如何纠正?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>