最后,我想要一个案例类交换,以便交换(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)
^
所以我的问题是:
答案 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)
问题是你不能静态地知道a
是Set2
- 就编译器而言你称之为Set(as: A*)
并且回到某种{{1} }}
您可以使用shapeless sized collections强制执行静态已知的集合大小。