我了解到Scala不会检查对象私有(private[this]
)或对象保护(protected[this]
)定义的方差位置。为什么不检查它们是否安全?
我已经阅读了一些与之相关的材料,但未能找到完整的答案。首先,Odersky等人的“Scala编程”说:
http://www.artima.com/pins1ed/type-parameterization.html#19.7
事实证明,从定义它们的同一对象访问变量不会导致方差问题。直观的解释是,为了构造一个方差会导致类型错误的情况,你需要引用一个包含对象,该对象具有比定义对象的类型更静态的类型。
我不确定作者的意思是“a 包含对象”和“静态弱类型”。这里更优选代码示例。
其次,“senia”在Scala Modifiers and Type parametrization中给出了一个很好的例子,它显示了类 - 私有(private
)字段可能带有差异的问题。
这个例子让我相信为什么应该检查类私有成员的差异位置,但是没有给出我们不必检查对象私有/受保护定义的原因的答案。我知道像getOtherCache()
这样的代码不能用object-private字段写。但它并未证明对象 - 私有/预测定义的无害性,我们还没有编写一个程序,对象 - 私有/预测定义会导致方差问题。
第三,在讨论如何在Scala中实现函数memoization时,Michid简要地提到了这个主题:
http://michid.wordpress.com/2009/02/23/function_mem/
class Memoize1[-T, +R](f: T => R) extends (T => R) { ... private[this] val vals = mutable.Map.empty[T, R] ... }
但是,由于vals仅从其包含实例访问,因此不会导致方差问题。
不幸的是,它没有回答我的问题“与方差相关的访问控制如何(或为什么)?”。
您能否更详细地解释不检查对象 - 私有/受保护定义的方差位置(或提供一些参考)的基本原理?
答案 0 :(得分:5)
只有在对象的编译时和运行时类型不同时才会出现方差问题:
val a: List[Any] = List("foo"): List[String]
此处a
具有静态较弱的类型(List[Any]
)而非定义的List[String]
)。此外,这同样适用于包含对象(即列表的元素)。 (静态类型Any
,已定义类型String
)。
如果我们有对象私有(或受对象保护)字段,则不会发生这种情况:
trait A[-T] {
protected[this] val x: T
}
当我们访问x
时,我们可以确定它实际上是T
类型,即使A
是反变量的,因为this
引用不能 - 在某个地方施展。 (我们总是完全了解自己的类型。)
所以当我们回到奥德斯基的话时,让我们来看看:
val cont: A[String] = new A[Any] { ... }
cont.x // BAD! Is `Any`, not `String`
cont
是对具有静态弱于定义的对象的引用,这就是不允许引用x
的原因。使用this指针不会发生这种上转情况,因此以下情况可以:
trait B[-T] extends A[T] {
def foo() {
// here, this has always the most specific type.
val tmp: T = this.x
// do stuff
}
}