扩展Scala中的现有数据结构

时间:2010-05-09 09:19:10

标签: data-structures scala scala-2.8

我在Scala中定义了一个普通的树。

sealed abstract class Tree
object Tree {
  case class Node (...) extends Tree
  case class Leaf (...) extends Tree
}

现在我想将一个成员变量添加到树中的所有节点和叶子。 是否可以使用extend关键字或者我是否必须通过添加[T]?

来修改树类

更新
似乎我的问题被误解了。 示例应清除它:

我需要这个树结构(实际上更复杂的东西)在一个上下文中有两个双打。 在另一个上下文中,我需要它有一个字符串。然而在另一种情况下,我需要没有任何(额外)成员的纯树。我希望前两个变种第三种变体。 伪代码:

DTree extends Tree with Touple2[Double, Double]
object DTree {
  case class Node (...) extends Tree.Node with Touple2[Double, Double]
  case class Leaf (...) extends Tree.Leaf with Touple2[Double, Double]
}

STree extends Tree with String
object DTree {
  case class Node (...) extends Tree.Node with String
  case class Leaf (...) extends Tree.Leaf with String
}

...

def f (t : Tree) { ... }

我希望f能够处理所有树木。

4 个答案:

答案 0 :(得分:2)

如果我理解正确,您希望某些树节点具有包含该类型字段的类型。我认为abstract type是您正在寻找的。它们就像泛型一样,但更适合于分类。这样的事情。

sealed abstract class Tree

trait TypedTree {
  type T
  val value:T
}

然后,当我修改你的例子时,结果是:

trait DTree extends TypedTree {
  type T = Touple2[Double, Double]
}
object DTree {
  case class Node (...) extends Tree.Node with DTree 
  case class Leaf (...) extends Tree.Leaf with DTree 
}

trait STree extends TypedTree {
  type T = String
}
object DTree {
  case class Node (...) extends Tree.Node with STree
  case class Leaf (...) extends Tree.Leaf with STree
}

这增加了一个间接级别。但我觉得你在一步中概念化了两个必要的东西。

答案 1 :(得分:0)

您不必修改树类,因为您始终可以在树和Node / Leaf之间创建中间子类:


abstract class ExtraMember[T](member:T) extends Tree

但是,如果您希望将额外成员作为参数传递,则无法通过将特征混合到Node和Leaf来实现此目的。

答案 2 :(得分:0)

抽象类可能有构造函数(特征可能没有),因此您可以将公共元素放在abstract class Tree中:

abstract
class Tree(te1: String, te2: Int)

case
class Node(...)
extends Tree(te1Arg, te2Arg)

等等。请注意,您必须在子类定义的extends子句中提供基类构造函数参数。

答案 3 :(得分:0)

如果您要添加的成员对所有Tree个对象(和子类)都有效,那么逻辑位置就是将它们放在Tree对象本身中。

你有两种技术可供选择。正如其他人所提到的,你可以在抽象类上创建这些构造函数参数:

sealed abstract class Tree(prop1: String, prop2: Int)

case class Node(prop1: String, prop2: Int) extends Tree(prop1, prop2)

你也可以使它们成为常规的val / vars并专注于子类。这可以说是一个更好的解决方案,因为它可以更容易地计算这些属性,而不是简单地通过构造函数对它们进行菊花链连接:

sealed abstract class Tree {
  def prop1 : String
  def prop2 : Int
}

case class Node(a:String, b:Int) extends Tree {
  lazy val prop1 = "[" + a + "]"
  lazy val prop2 = b + 42
}

在这里使用延迟val可以更容易地推断对象的初始化顺序,如果从不使用该属性,它还可以避免任何计算开销。这也很好地说明了Scala中的方法如何通过属性实现,即所谓的统一访问原则。

如果采用这种方法,那么也可以通过特征引入属性:

sealed abstract class Tree

trait TreeExtras {
  def prop1 : String
  def prop2 : Int
}

case class Node(a:String, b:Int) extends Tree with TreeExtras {
  lazy val prop1 = "[" + a + "]"
  lazy val prop2 = b + 42
}

您也应该随意使用自我类型等。