在scala中,是否有可能只有两个元素的Set?
最后,我想有一个案例类交换,以便交换(a,b)==交换(b,a)。在scala中,是否有可能只有两个元素的Set?
我想我可以用两个元素的集合,它相当这项工作:
scala> case class Swap(val s:Set[Int])
defined class Swap
scala> Swap(Set(2, 1)) == Swap(Set(1, 2))
res0: Boolean = true
但这允许任意数量的元素,我想我的元素限制两个 。我发现类Set.Set2,这是一个不变的设置有两个元素的默认实现,但它不工作的它我尝试的方式,或变化:
scala> val a = Set(2, 1)
a: scala.collection.immutable.Set[Int] = Set(2, 1)
scala> a.getClass
res3: Class[_ <: scala.collection.immutable.Set[Int]] = class scala.collection.immutable.Set$Set2
scala> case class Swap(val s:Set.Set2[Int])
defined class Swap
scala> val swp = Swap(a)
<console>:10: error: type mismatch;
found : scala.collection.immutable.Set[Int]
required: Set.Set2[Int]
val swp = Swap(a)
^
所以我的问题是:
- 有没有办法在我尝试使用Set2?
- 有没有更好的方法来实现我的案例类Swap?我读过一个人不应该在案例课程中重写equals,尽管这是我的第一个想法。
这是一个通用的实现 -
import scala.collection.immutable.Set.Set2
def set2[T](a: T, b: T): Set2[T] = Set(a, b).asInstanceOf[Set2[T]]
case class Swap[T](s: Set2[T])
Swap(set2(1,2)) == Swap(set2(2,1)) //true
您的解决方案没有工作的原因是因为签名的
Set(elems: A*): Set
在2元的情况下,具体类型将是SET2但编译器不知道,所以你必须将它投到Set2
您可以随时隐藏Swap
实施细则,在这种情况下,你居然应该。
你可以使用Set
执行或者你可以实现它:
// invariant a <= b
class Swap private (val a: Int, val b: Int)
object Swap {
def apply(a: Int, b: Int): Swap =
if (a <= b) new Swap(a, b) else new Swap(b, a)
}
不幸的是,你必须在这里使用class
并重新实现equals
hashCode
等自己,因为我们无法摆脱的scalac
自动生成apply
: related SO Q/A
并使Swap
上的所有功能保持不变。
然后等于比较本质上是this.a == other.a && this.b == other.b
,我们不需要关心交换了。
问题是,你不知道静态a
是Set2
- 就编译器而言,你叫Set(as: A*)
,并得到某种Set
。
您可以使用shapeless sized collections来执行一个静态已知的集合大小。
是的,我调用'Set(as:A *)',因为我找不到直接构建'Set2'的方法...... – 2015-02-06 09:56:22
是的,构造函数是'private [collections]'。你可以通过反射来调用它,或者可能更有用的模式匹配:'a match {case s2:Set2 => Swap(s2)}'。但这并不完全安全;如果'a'不是'Set2',它会在运行时抛出一个'MatchError'。 – lmm 2015-02-06 09:58:33
谢谢,这是我使用的解决方案。为了方便起见,我还添加了第二个构造函数'def this(t1:T,t2:T)= this(Set(t1,t2).asInstanceOf [Set2 [T]])',这允许我用'new Swap (t1,t2)'。 最后我用这种方式匹配模式: 'case Swap(s:Set2 [T])=> { val t1 = s.head val t2 = s.last ...} – 2015-02-06 13:00:58