在scala中,是否可以只使用两个元素Set?

时间:2015-02-06 08:51:04

标签: scala

最后,我想要一个案例类交换,以便交换(a,b)==交换(b,a)

我以为我可以使用一组两个元素,它完全可以胜任:

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,尽管这是我的第一个想法。

3 个答案:

答案 0 :(得分:3)

这是一个通用的实现 -

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

答案 1 :(得分:1)

您始终可以隐藏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:{ {3}}

使Swap上的所有函数都保持不变。

那么equals comparion基本上是this.a == other.a && this.b == other.b,我们不再需要关心交换了。

答案 2 :(得分:1)

问题是你不能静态地知道aSet2 - 就编译器而言你称之为Set(as: A*)并且回到某种{{1} }}

您可以使用shapeless sized collections强制执行静态已知的集合大小。