我有两个集合,其中一个列出派生类的实例。创建的集合类型不受我的控制,我无法确保两者都是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]]
答案 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}")