在 scala 2.13 中,为什么伴随对象的隐式范围有时可能未对齐?如何纠正?
In scala 2.13, why implicit scope of a companion object may sometimes be misaligned? How to correct it?
下面是一个测试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] {}
}
}
根据这篇文章:
Where does Scala look for implicits?
当使用类型 Handler[_]
时,特性 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 既是 class 又是对象名称,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
上面的None可以解释为什么handle2在范围内。可能是什么原因?
顺便说一句:对于那些将隐式视为一个重要的 Scala 特性的人:隐式是实现类型的唯一方法 class,如果你想用最少的样板来实现它,有时上面的模式可以是唯一的选择。
要点 3 here 解释了所讨论类型的前缀中的 implicits/givens 有助于其隐式作用域(在 Scala 3 中,如果它是一个包则不是)。因此对于类型 Sys1.Handler[Long]
隐含在 Sys1
中是在隐含范围内,因为 Sys1
是一个非包前缀。
handle1
不在隐式范围内,因为对象 Sys1
中的对象 Handler
不是特征 System
中特征 Handler
的伴随对象。
下面是一个测试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] {}
}
}
根据这篇文章:
Where does Scala look for implicits?
当使用类型 Handler[_]
时,特性 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 既是 class 又是对象名称,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
上面的None可以解释为什么handle2在范围内。可能是什么原因?
顺便说一句:对于那些将隐式视为一个重要的 Scala 特性的人:隐式是实现类型的唯一方法 class,如果你想用最少的样板来实现它,有时上面的模式可以是唯一的选择。
要点 3 here 解释了所讨论类型的前缀中的 implicits/givens 有助于其隐式作用域(在 Scala 3 中,如果它是一个包则不是)。因此对于类型 Sys1.Handler[Long]
隐含在 Sys1
中是在隐含范围内,因为 Sys1
是一个非包前缀。
handle1
不在隐式范围内,因为对象 Sys1
中的对象 Handler
不是特征 System
中特征 Handler
的伴随对象。