使用具体类型扩展Scala Set

时间:2010-12-11 13:17:05

标签: scala scala-2.8

真的很难找出用一个代表一组具体类型的类来扩展不可变集合。我这样做是为了尝试创建一个不错的DSL。

我想要一个类Thing,当你将'things'添加到一起时,你会得到一个ThingSet对象,它扩展了Set。

class Thing(val name:String){
  def +(other: Thing):ThingSet = new ThingSet() + other
}

我无法弄清楚如何制作ThingSet对象。我知道我需要混合GenericSetTemplate,SetLike等特征。但我无法让它发挥作用。

拜托,任何人都可以给我一些指示,因为我找不到任何明确的东西可以借鉴。我试过看BitSet和HashSet实现,但迷路了。

2 个答案:

答案 0 :(得分:9)

this Daily Scala帖子和源代码改编为BitSet,这是一个很好的例子,因为它不是参数化集合,而且非常简短。

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
    }
}

答案 1 :(得分:3)

从Set上的scaladocs,我认为你只需要实现4或5种方法。在这种情况下,我决定使用支持Seq [Thing]来创建我的实际集合实现。

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"))

结果:

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

注意:我认为你必须在脚本文件而不是REPL中运行它,因为Thing和ThingSet之间存在周期性依赖。