如何扩展不可变集合并添加字段成员?
How to extend an immutable collection and add a field member?
我想像这样将成员 someProperty
添加到不可变的 Set
,
class MySet[A](val someProperty: T, set: Set[A])
extends Set[A] with SetLike[A, MySet[A]] {
//...
}
使得 MySet
表现得像 Set
。但是,我不够聪明,无法实现在转换后会保留 someProperty
的 Builder
/CanBuildFrom
(例如 here)。我唯一的解决方案是手动将 MySet
与 map、foldLeft 等连接起来,使其表现得像 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...
}
但这似乎很乏味。有没有更好的方法在不进入可变领域的情况下做到这一点?谢谢。
首先,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]
或集合伴侣对象的其他基础 class。这给出了 MySet.empty[A]
和 MySet.apply[A](as: A*)
的实现,它们使用 someProperty
.
的默认值创建 MySet
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]
}
}
我想像这样将成员 someProperty
添加到不可变的 Set
,
class MySet[A](val someProperty: T, set: Set[A])
extends Set[A] with SetLike[A, MySet[A]] {
//...
}
使得 MySet
表现得像 Set
。但是,我不够聪明,无法实现在转换后会保留 someProperty
的 Builder
/CanBuildFrom
(例如 here)。我唯一的解决方案是手动将 MySet
与 map、foldLeft 等连接起来,使其表现得像 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...
}
但这似乎很乏味。有没有更好的方法在不进入可变领域的情况下做到这一点?谢谢。
首先,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]
或集合伴侣对象的其他基础 class。这给出了 MySet.empty[A]
和 MySet.apply[A](as: A*)
的实现,它们使用 someProperty
.
MySet
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]
}
}