2016-03-03 38 views
2

我想成员someProperty添加到一个不变的Set这样,如何扩展一个不可变的集合并添加一个字段成员?

class MySet[A](val someProperty: T, set: Set[A]) 
    extends Set[A] with SetLike[A, MySet[A]] { 
    //... 
} 

这样MySet表现得像Set。但是,我不够聪明,无法实施在转换后保留somePropertyBuilder/CanBuildFrom(例如here)。我唯一的解决办法就是手动线了MySet地图,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... 

} 

但这似乎很乏味。有没有更好的方式来做到这一点,而不进入可变的领土?谢谢。

+0

如果我理解正确,你会发现延长乏味,但你发现不会延长繁琐以及? :) – slouc

+0

@slouc我发现没有延长繁琐,并延长困难/不可能。尽管如此,将会更好。 – Lasf

+0

我同意扩展是困难的,你提供了一些证明你自己的SO链接。如果你想避免手动设置地图和foldLefts,你可以从Set到你的类的隐式转换,它为你的设置增加了一层额外的功能。基本上你会[继承](https://en.wikipedia.org/wiki/Composition_over_inheritance)。这也是您提供的链接中建议的内容。 – slouc

回答

1

首先,为someProperty设置一个默认值(零)会使事情变得更容易一些。在你的情况下,我想你可以选择MustMustNot,这取决于你的问题的具体情况。

我假设的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*)的实现,其使用默认值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] 
    } 
} 
+0

我不是这方面的专家,因此欢迎任何建议和更正。无论如何,这似乎工作。 – Kolmar

相关问题