为什么不检查对象私有或对象保护定义的方差位置是否安全?

dki*_*kim 5 scala covariance contravariance

我了解到Scala不会检查object-private(private[this])或object-protected(protected[this])定义的方差位置.为什么不检查它们是否安全?

我已经阅读了一些与之相关的材料,但未能找到完整的答案.首先,Odersky等人的"Scala编程"说:

http://www.artima.com/pins1ed/type-parameterization.html#19.7

事实证明,从定义它们的同一对象访问变量不会导致方差问题.直观的解释是,为了构造方差会导致类型错误的情况,您需要引用一个包含对象,该对象具有比定义对象的类型更静态的类型.

我不确定作者的意思是" 包含对象"和" 静态较弱的类型".这里更优选代码示例.

其次,"senia"在Scala Modifiers和Type参数化中给出了一个很好的例子,它显示了class-private(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]
  ...
}
Run Code Online (Sandbox Code Playgroud)

但是,由于仅从包含实例访问val,因此不会导致方差问题.

不幸的是,它没有回答我的问题"如何(或为什么)是与方差相关的访问控制?".

您能否更详细地解释不检查对象 - 私有/受保护定义的方差位置(或提供一些参考)的基本原理?

gzm*_*zm0 5

只有在对象的编译时和运行时类型不同时才会出现方差问题:

val a: List[Any] = List("foo"): List[String]
Run Code Online (Sandbox Code Playgroud)

这里a有一个静态较弱的类型(List[Any])而不是定义的(List[String]).此外,这同样适用于包含对象(即列表的元素).(静态类型Any,定义类型String).

如果我们有对象私有(或受对象保护)字段,则不会发生这种情况:

trait A[-T] {
  protected[this] val x: T
}
Run Code Online (Sandbox Code Playgroud)

当我们访问时,x我们可以确定它实际上是类型T,即使A是反式变体,因为this引用不能在某处向上转换.(我们总是完全了解自己的自我类型).

所以当我们回到奥德斯基的话时,让我们来看看:

val cont: A[String] = new A[Any] { ... }
cont.x // BAD! Is `Any`, not `String`
Run Code Online (Sandbox Code Playgroud)

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
  }
}
Run Code Online (Sandbox Code Playgroud)