我想扩展一个类为mutable.HashMap []的类,如下所示:
class Father
class Son extends Father
class C1{
val m = new mutable.HashMap[Int, Father]()
}
class C2 extends C1{
override val m = new mutable.HashMap[Int, Son]()
}
并收到错误:
错误:(19,16)覆盖类型C1中的值m scala.collection.mutable.HashMap [中等,ScalaByExample.Father];价值m 具有不兼容的类型覆盖val m = new mutable.HashMapInt, 子
我发现immutable.HashMap
是协变的,但mutable.HashMap
是不变的。如果将mutable.HashMap
替换为immutable.HashMap
,则可以使用。
所以我的两个问题是:
如何使用mutable.HashMap?
为什么scala的作者会像这样设计HashMap?
答案 0 :(得分:4)
可变地图是不变的,因为写入它们不会是安全的。例如考虑以下函数:
def f(o: C1) {
o.m(42) = new Father
}
这种方法非常好。但是,如果您传递C2
的实例作为o
的值,则会因为Map[Int, Son]
不允许包含Father
个对象而中断。因此,您对C2
的定义是错误的。
答案 1 :(得分:1)
Scala中的不可变集合能够协变的原因是因为如果要添加元素,您实际上将创建一个具有(可能)不同底层类型的全新对象。根据需要,新地图的基础类型将与原始地图的类型相同或超类型。
因此,在您的情况下,如果您从 HashMap [Int,Son] 的实例开始并添加一个父的对象,则生成的地图实际上是属于 HashMap [Int,Father] 。新地图中除了一个元素之外的所有元素实际上都是 Son 对象( Son 是父的子类)。只有您添加的那个实际上才是父。但就编译器而言,它所知道的新地图是所有元素都是父的类型。
如果像我想象的那样,你的地图类型对你来说比可变性更重要,那么你应该切换到不可变类型。很难在这样的集合中真正需要可变性。