【问题标题】:Extend Scala Set with concrete type使用具体类型扩展 Scala Set
【发布时间】:2011-05-23 22:42:01
【问题描述】:

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

我想要一个 Thing 类,当你将“事物”加在一起时,你会得到一个扩展 Set 的 ThingSet 对象。

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

我只是不知道如何制作 ThingSet 对象。我知道我需要混合 GenericSetTemplate、SetLike 等特征。但我就是做不到。

请,任何人都可以给我一些指示,因为我找不到任何足够明确的东西来学习。我试过查看 BitSet 和 HashSet 实现,但迷路了。

【问题讨论】:

  • 嗯...您忘记将this 添加到ThingSet,因此您可能需要修复该错误。 :-)

标签: scala scala-2.8


【解决方案1】:

改编自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
    }
}

【讨论】:

    【解决方案2】:

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

    注意:由于 Thing 和 ThingSet 之间的循环依赖关系,我认为您必须在脚本文件而不是 REPL 中运行它。

    【讨论】:

    • 除了前两个之外,我实现的 Set 方法都是如此。你指的是什么操作?
    • mapfilter 等方法。
    • 这是错误的实现,我不小心 +1 了。它不遵守集合规则。产生与原始集合不同的重复元素 new ThingSet(Seq(new Thing("dog"), new Thing("cat"), new Thing("dog"))) res1: ThingSet = Set(dog, cat, dog) Set( "dog","cat","dog") res2: scala.collection.immutable.Set[String] = Set(dog, cat)
    猜你喜欢
    • 2012-11-18
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 2021-11-29
    • 1970-01-01
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多