Extend Scala Set with concrete type

后端 未结 2 578
情书的邮戳
情书的邮戳 2021-01-14 17:26

Really struggling to figure out extending the immutable Set with a class that will represent a Set of concrete type. I\'m doing this to try and create a nice DSL.

I

相关标签:
2条回答
  • 2021-01-14 17:44

    From the scaladocs on Set, I think you just have to implement 4 or 5 methods. In this case I've decided to use a backing Seq[Thing] to create my actual set implementation.

    class ThingSet(things: Seq[Thing]) extends Set[Thing] {
      def contains(key: Thing) = { things.contains(key) }
      def iterator: Iterator[Thing] = { things.iterator }
      def +(elem: Thing) = new ThingSet(things :+ elem)
      def -(elem: Thing) = new ThingSet(things.filterNot(_ == elem))
      override def empty = new ThingSet(Nil)
    }
    
    class Thing(val name: String) {
      def +(other: Thing) = { new ThingSet(List(this,other)) }
      override def toString = name
    }
    
    val thing = new Thing("I'm a new thing")
    println(thing + new Thing("I'm some other thing"))
    

    results in:

    Set(I'm a new thing, I'm some other thing)
    

    note: I think you have to run this in a script file rather than the REPL because of the cyclical dependency between Thing and ThingSet.

    0 讨论(0)
  • 2021-01-14 18:05

    Adapting from this Daily Scala post as well as the source to BitSet, which is a wonderful example here because it is not a parameterized collection, and is rather short and simple.

    import scala.collection.SetLike
    import scala.collection.generic.{GenericSetTemplate, GenericCompanion, CanBuildFrom}
    import scala.collection.mutable.{Builder, SetBuilder}
    
    class ThingSet(seq : Thing*) extends Set[Thing] 
                                 with SetLike[Thing, ThingSet]
                                 with Serializable {
        override def empty: ThingSet = new ThingSet()
        def + (elem: Thing) : ThingSet = if (seq contains elem) this 
            else new ThingSet(elem +: seq: _*)
        def - (elem: Thing) : ThingSet = if (!(seq contains elem)) this
            else new ThingSet(seq filterNot (elem ==): _*)
        def contains (elem: Thing) : Boolean = seq exists (elem ==)
        def iterator : Iterator[Thing] = seq.iterator
    }
    
    object ThingSet {
        def empty: ThingSet = new ThingSet()
        def newBuilder: Builder[Thing, ThingSet] = new SetBuilder[Thing, ThingSet](empty)
        def apply(elems: Thing*): ThingSet = (empty /: elems) (_ + _)
        def thingSetCanBuildFrom = new CanBuildFrom[ThingSet, Thing, ThingSet] {
            def apply(from: ThingSet) = newBuilder
            def apply() = newBuilder
        }
    }
    
    0 讨论(0)
提交回复
热议问题