6

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

我已经阅读了一些与之相关的材料,但还没有找到完整的答案。首先,Odersky 等人的“Scala 编程”说:

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

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

我不确定作者所说的“包含对象”和“静态较弱的类型”究竟是什么意思。代码示例在这里会更可取。

其次,“senia”在Scala Modifiers and Type parametrization中给出了一个很好的例子,它显示了 class-private ( private) 字段可能存在的差异问题。该示例使我相信为什么应该检查类私有成员的方差位置,但没有给出关于我们不必检查对象私有/受保护定义的原因的答案。我知道这样的代码getOtherCache()不能用对象私有字段编写。但是它并没有证明我们没有编写一个程序来证明对象私有/投影定义会导致方差问题。

第三,Michid 在描述如何在 Scala 中实现函数记忆时简要提到了这个话题:

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 只能从其包含的实例中访问,它不会导致方差问题。

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

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

4

1 回答 1

6

仅当对象的编译时和运行时类型不同时,才会出现方差问题:

val a: List[Any] = List("foo"): List[String]

这里a的类型 ( ) 在静态上List[Any]比定义的 ( List[String]) 弱。此外,这同样适用于包含对象(即列表的元素)。(静态类型Any,定义类型String)。

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

trait A[-T] {
  protected[this] val x: T
}

当我们访问时,x我们可以确定它实际上是 type 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
  }
}
于 2013-05-07T23:11:10.953 回答