假设我想在scala中实现某种不可变集合,我希望它有2个方法 - 添加和包含。我也认为Set[Cat]
是一组Set[Animals]
(因此我希望它被解析为MySet[+A]
)。
所以我写了这样的东西
class MySet[+A] {
def add[B >: A](elem: B): MySet[B]
}
在我尝试实现contains
方法之前,这似乎没问题。在我看来,类似方法的最佳拟合签名应为def contains(elem: A): Boolean
,因为一组Cat
只能包含Cat
s。它不能包含Dog
或任何其他动物。
当然scala抱怨这样的方法:Covariant type A occurs in a contravariant position in type A of value elem
我甚至理解为什么。
我的问题是如何说服scala我的方法contains
不会以任何方式改变我的集合,并且可以安全地将A
类型的元素传递给它。
答案 0 :(得分:2)
问题不在于scala害怕你会改变这个集合。
问题是,因为你的集合是协变的,MySet[Cat]
是MySet[Animal]
的子类。因此,如果后者被允许def contains(a: Animal)
,那么前者也必须有一个。{/ p>
你可以使用与.add
:
def contains[B >: A](elem: B): Boolean
请注意,标准scala库中的不可变Set
实际上是元素类型中的不变。那是因为他们希望它作为一个函数A => Boolean
工作,这需要它有apply(a: A)
,这与你所说的问题基本相同。
并且回馈我的昵称BTW,这不酷,伙计!
答案 1 :(得分:1)
如果对于类型安全 contains
,您可以尝试为implicits
创建类型安全 contains
来解决Set
} contains
方法参数必须是cotravariant
问题,例如:
//implicit bound for `MySet` with the type `A`, so in there `A` is invariant type.
implicit class TypeSafeMySetContains[A](s: MySet[A]) {
def has(a: A): Boolean = s.contains(a) // invoke the `contains` method check
}
MySet(1, 2, 3) has "3" // the compiler will throw type mismatch error
MySet(1, 2, 3) has 3