Scala:协变类中的const方法

时间:2017-10-08 14:50:01

标签: scala

假设我想在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类型的元素传递给它。

2 个答案:

答案 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