Scala修饰符和类型参数化

Scala修饰符和类型参数化,scala,Scala,我正在创建一个备忘录类 每个类记录一个函数类型,并具有以下定义: 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],则会出现以下错误: con

我正在创建一个备忘录类

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

 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突然干扰了贴图的不变类型?
修饰符是如何影响类型参数化的?

我并不完全理解,但第45页的第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")
}

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

假设您可以删除
[此]

如果没有
[此]
,您可以添加方法
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]!

在“对象私有成员只能从定义它们的对象内访问。事实证明,从定义它们的同一对象访问变量不会导致差异问题。”

Tangential:
cache.getOrElseUpdate(t,f(t))
-我相信无论是否在缓存中,每次都会调用
f(t)
。需要更多的惰性。实际上,它是一个按名称调用参数(根据),这意味着如果
getOrElseUpdate
需要,它不会得到评估。进一步的测试证实了这一点。啊,你是对的。我需要更多地熟悉Scala。我是个新手,这可能没有意义。。。但是,在“this”实例的上下文之外,getter for cache上的关键参数是否不明确?例如,如果我引用了一个MemoizedFunction[String,String]作为一个MemoizedFunction[Object,String],那么缓存类型似乎是关闭的,所以这是一个封装问题。差异得到控制,因此没有问题。令人惊叹的。谢谢,这是一个很好的例子。我检查了源代码(),没有任何差异。因此,你的例子给出了一个错误是有道理的。谢谢你提供这些信息。@JaimeJorge:听起来可能很傻,但你知道有在线文档吗?它比源代码更方便:)我知道。我只是查看了代码以确定差异(如果API文档保留了任何差异注释)。看看(例如)我现在知道它在API@JaimeJorge:没有代码或文档:映射的键类型参数不能是相反的
Map[A,B]
不能是
Map[B,B]
,因为
keys
方法返回
Iterable[TKey]