这个问题与this one有关:是否可以在Scala中创建一个类似于Set的类(意味着它扩展了Set特性),其中用于定义包含关系的等式由用户定义而不是?测试此方法是否真正有效的一种方法是检查==是否返回相同的集合类型。// typeclass for equalitytrait Equals[T] { def isEqual(t1: T, t2: T): Boolean}// an object representing plane coordinatescase class Coordinate(i: Int, j: Int)// an equality saying that 2 coordinates are equal if they are on// the same horizontal lineimplicit def horizontalEquality: Equals[Coordinate] = new Equals[Coordinate] { def isEqual(t1: Coordinate, t2: Coordinate) = t1.i == t2.i}// we create an EqualitySet[T] where T must verify [T : Equals]val set = EqualitySet[Coordinate]()// set2 must be of type EqualitySet[Coordinate]val set2 = set.filter(_.i > 0) (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 在Miles Sabin(@milessabin)的Scala培训中,我们作为小组创建了此解决方案。import scala.collection.mutable.ListBufferimport scala.collection.generic.CanBuildFromimport scala.collection.SetLikeimport scala.collection.mutable.Builder/** * we extend Set[T] to provide the Set-like interface * we extends SetLike[T, EqualitySet[T]] to specify that Set methods will return * instances of type EqualitySet (and not simply Set) */trait EqualitySet[T] extends Set[T] with SetLike[T, EqualitySet[T]] { outer => /** we need to provide an Equals[T] instance to create an EqualitySet[T] */ implicit def equality: Equals[T] /** our internal implementation as a list of elements */ protected val set = ListBuffer[T]() /** we need to implements those 4 methods */ def contains(t: T) = set.exists(equality.isEqual(_, t)) def +(t: T) = { if (!contains(t)) set += t; this } def -(t: T) = { set -= t; this } def iterator = set.iterator /** we must be able to provide an empty set with the proper equality definition */ override def empty = new EqualitySet[T] { override def equality = outer.equality }}/** * Companion object for the EqualitySet class */object EqualitySet { /** * this implicit is absolutely necessary to be able to preserve the resulting * collection type when calling `filter` */ implicit def canBuildFrom[T] = new CanBuildFrom[EqualitySet[T], T, EqualitySet[T]] { def apply(from: EqualitySet[T]): Builder[T, EqualitySet[T]] = new Builder[T, EqualitySet[T]] { // use a ListBuffer internally to accumulate elements private val elems = ListBuffer[T]() def +=(t: T) = { if (!elems.exists(from.equality.isEqual(_, t))) elems += t this } def clear() = elems.clear // when we finish building the collection // we can return an EqualitySet with the original equality relation def result() = new EqualitySet[T] { override val set = elems override def equality = from.equality } } def apply(): Builder[T, EqualitySet[T]] = sys.error("this can't be implemented, because no equality instance is provided") } /** @return an EqualitySet for a type T having an Equals instance */ def apply[T : Equals](ts: T*) = { var set = new EqualitySet[T] { def equality = implicitly[Equals[T]] }.empty ts.foreach { t => set += t } set }}然后,当我们使用上面的代码时,我们得到:scala> val set = EqualitySet[Coordinate](Coordinate(-1, 2), Coordinate(-1, 3), Coordinate(1, 4))set: java.lang.Object with test.EqualitySet[Coordinate] = Set(Coordinate(-1,2) Coordinate(1,4))scala> val set2 = set.filter(_.i > 0)// still an EqualitySet[Coordinate] \o/ */set2: test.EqualitySet[Coordinate] = Set(Coordinate(1,4)) (adsbygoogle = window.adsbygoogle || []).push({});
09-11 20:02