我想将成员someProperty
添加到这样的不可变Set
,
class MySet[A](val someProperty: T, set: Set[A])
extends Set[A] with SetLike[A, MySet[A]] {
//...
}
这样MySet
的行为就像Set
。但是,我并不聪明地实施Builder
/ CanBuildFrom
(例如here),这会在转换后保留someProperty
。我唯一的解决方案是使用map,foldLeft等手动连接MySet
,使其行为类似于Set
class MySet[A](val someProperty: T, set: Set[A]) {
def map[B](f: (A) => B)(implicit bf: CanBuildFrom[Set[A], B, Set[B]]): MySet[B] =
new MySet[B](someProperty, set.map[B, Set[B]](f)(bf))
//more methods here...
}
但这似乎很乏味。有没有更好的方法来做到这一点而不进入可变领域?感谢。
答案 0 :(得分:1)
首先,someProperty
的默认值(零)使事情变得容易一些。在您的情况下,我猜您可以选择Must
或MustNot
,具体取决于您问题的具体情况。
我将假设T
的以下定义及其默认值:
sealed trait T
object T {
final val Default: T = Must
}
case object Must extends T
case object MustNot extends T
case object Should extends T
您可以为MySet
实施以下实施,将大多数操作推迟到其set
属性,将一些操作推迟到其伴随对象。另请注意,filter
等某些方法不使用CanBuildFrom
,因此您必须为其覆盖newBuilder
方法。
class MySet[A](val someProperty: T, set: Set[A])
extends Set[A] with SetLike[A, MySet[A]] {
def +(elem: A): MySet[A] = new MySet[A](someProperty, set + elem)
def -(elem: A): MySet[A] = new MySet[A](someProperty, set - elem)
def contains(elem: A): Boolean = set contains elem
def iterator: Iterator[A] = set.iterator
override def companion = MySet
override def empty: MySet[A] = MySet.empty[A]
// Required for `filter`, `take`, `drop`, etc. to preserve `someProperty`.
override def newBuilder: mutable.Builder[A, MySet[A]] =
MySet.newBuilder[A](someProperty)
}
对于伴侣object MySet
,可以扩展SetFactory[MySet]
或其他一些基类的集合伴随对象。这提供了MySet.empty[A]
和MySet.apply[A](as: A*)
的实现,使用默认值MySet
创建someProperty
。
object MySet extends SetFactory[MySet] {
// For the builder you can defer to the standard `mutable.SetBuilder`
class MySetBuilder[A](someProperty: T) extends
mutable.SetBuilder[A, MySet[A]](new MySet(someProperty, Set.empty))
def newBuilder[A] = newBuilder[A](T.Default)
// Additional method for creating a builder with a known value of `someProperty`
def newBuilder[A](someProperty: T) = new MySetBuilder[A](someProperty)
// You may also want to define `apply` and `empty` methods
// that take a known `someProperty`.
// `CanBuildFrom` from `MySet[_]` to `MySet[A]`.
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, MySet[A]] =
new CanBuildFrom[Coll, A, MySet[A]] {
// This is the method that makes
// e.g. `map`, `flatMap`, `collect` preserve `someProperty`
def apply(from: Coll): mutable.Builder[A, MySet[A]] =
newBuilder[A](from.someProperty)
def apply(): mutable.Builder[A, MySet[A]] = newBuilder[A]
}
}