2017-10-06 57 views
2

我有两组,其中一组列出派生类的实例。创建的设置类型超出了我的控制范围,我无法确定两者都是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]

注:乙<:A,但性状的柴油发电机组是在类型A.不变

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

​​

回答

0

当您创建集作为Set(new A("1"), new A("2")),它assignes类型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类,不鼓励):

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}") 
+0

“但是,如果你初始化变量如下:”我想在我的问题写这是我做不到的。在需要其B类型的其他环境中,我需要set23。 “ – Suma

+0

”由此产生的交集是空的“您是对的,我已经简化了代码。我已将A更改为一个案例类 - 我知道从案例类派生出来是不好的做法,但就此问题而言,这是如何确保等于被覆盖的最短途径。 – Suma

+0

'case class'的例子只是为了这个问题的目的,它适用于这个目的。我很抱歉,但通过扩展如何正确地覆盖平等,我没有更接近实现我的目标,答案的核心部分仍然避免了如何交叉两组需要不同类型的问题。 – Suma