相交两个类,一个类和一个派生类

时间:2017-10-06 08:51:24

标签: scala collections set covariance

我有两个集合,其中一个列出派生类的实例。创建的集合类型不受我的控制,我无法确保两者都是Set[A]set23用于我需要其类型为Set[B]的其他上下文中。我想交叉:

case class A(name: String)
class B(name: String) extends A(name)

val set12 = Set(new A("1"), new A("2"))
val set23 = Set(new B("2"), new B("3"))

set12 intersect set23 // does not work

错误是:

  

类型不匹配;   发现:scala.collection.immutable.Set [B]

     

必需:scala.collection.GenSet [A]

     

注意:B<:A,但特性GenSet在A类中是不变的。

我知道Set不是协变的,是否有一些干净的解决方法而不重建集合?以下是有效的,但我不想使用asInstanceOf

set12 intersect set23.asInstanceOf[Set[A]]

1 个答案:

答案 0 :(得分:0)

当您将集合创建为Set(new A("1"), new A("2"))时,它会将类型Set[A]分配给结果值。 当您将集合创建为Set(new B("2"), new B("3"))时,它会将类型Set[B]分配给结果值。

因此,结果集是不同的类型,不能相交。但是如果你按如下方式初始化你的变量:

val set12: Set[A] = Set(new A("1"), new A("2"))
val set23: Set[A] = Set(new B("2"), new B("3"))

然后,您自己分配类型。由于结果值具有相同的类型,因此您可以交叉并执行其他操作。

例如,您可以使用intersect,如下所示:

val as: Set[A] = set12 intersect set23  // gives empty set as intersection

在上面的示例中,生成的交集是空的,因为它们没有相同的对象。

要成功进行比较,您还应该覆盖类的equals方法。在您的情况下,仅覆盖A就足够了。 以下是一个未经推荐但有效的方法(因为不鼓励扩展案例类别):

case class A(name: String) {
  override def equals(obj: scala.Any): Boolean = obj match {
    case A(x) => x.equals(name)
    case _ => false
  }
}

class B(name: String) extends A(name)

val set12: Set[A] = Set(new A("1"), new A("2"))
val set23: Set[A] = Set(new B("2"), new B("3"))

val as: Set[A] = set12 intersect set23  // gives A(2) as intersection
println(s"as = ${as}")