13

我正在创建一个记忆类。

每个类都记忆一个函数类型,并具有以下定义:

 class MemoizedFunction1[-T1, +R](f: T1 => R) {
    private[this] val cache = mutable.Map[T1, R]()
    def apply(t: T1): R = cache.getOrElseUpdate(t,f(t))
  }

这很好地编译并按预期工作。但是,如果我删除修改private[this]我得到以下错误:

contravariant type T1 occurs in invariant position in type => scala.collection.mutable.Map[T1,R] of value cache

为什么我去掉修饰符后,逆变类型T1突然干扰了Map的不变类型?修饰符如何影响类型参数化?

4

3 回答 3

7

假设您可以删除[this].

没有[this]你可以添加方法getOtherCache

class MemoizedFunction1[-T1, +R](f: T1 => R) { 
  private val cache = mutable.Map[T1, R]() // trait Map[A, B] extends Iterable[(A, B)] with Map[A, B] with MapLike[A, B, Map[A, B]]
  def apply(t: T1): R = cache.getOrElseUpdate(t,f(t))

  def getOtherCache(other: MemoizedFunction1[T1, R]) {
    val otherCache: mutable.Map[T1, R] = other.cache;
  }
}

class A
class B extends A

val mf1: MemoizedFunction1[B, B] = new MemoizedFunction1[B, B](b => b)

val mf2: MemoizedFunction1[B, B] = new MemoizedFunction1[A, B](a => new B)
// mf2 is MemoizedFunction1[B, B]
// mf2 contains mutable.Map[A, B]

mf1.getOtherCache(mf2) //Error! mf2.cache is NOT mutable.Map[B, B]!
于 2012-04-07T07:09:03.083 回答
6

并不是说我理解所有这些,但这在第 45 页的Scala 语言规范 2.9的第 4.5 节(变量注释)中得到了解决

对类的对象私有或对象保护的值、变量或方法(第 5.2 节)中的类型参数的引用不会检查它们的方差位置。在这些成员中,类型参数可以出现在任何地方,而不限制其合法的差异注释。

为了简化您的示例,根据规范,这很好:

class Inv[T]

class Foo[-T] {
  private[this]   val a: Inv[T] = sys.error("compiles")
  protected[this] val b: Inv[T] = sys.error("compiles")
}

但如果你删除[this]它会抱怨。在某种程度上,这是有道理的,因为如果它不是对象私有或受保护的,逆变返回类型可能会泄漏到对象之外并导致运行时错误。

于 2012-04-07T04:56:41.397 回答
2

Scala 编程在第19.7 节对象私有数据中涉及到这个主题:“对象私有成员只能从定义它们的对象内部访问。事实证明,从定义它们的同一对象访问变量不会引起方差问题。”

于 2012-04-07T11:19:25.987 回答