Data structures 在Scala中扩展现有数据结构

Data structures 在Scala中扩展现有数据结构,data-structures,scala,scala-2.8,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]来修改树类 更新: 我的问题似乎被误解了。 这个例子应该澄清这一点: 我需要这个树结构(实际上更复杂的东西)在一个上下文中有

我在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能够处理所有树。

您不必修改树类,因为您可以始终在树和节点/叶之间创建一个中间子类:


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

但是,如果希望将额外的成员作为参数传递,则不能通过将trait混合到Node和Leaf中来实现这一点。

抽象类可能有构造函数(trait可能没有),因此可以将公共元素放在
抽象类树中:

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

case
class Node(...)
extends Tree(te1Arg, te2Arg)
等等。请注意,您必须在子类定义的
extends
子句中提供基类构造函数参数。

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

你有两种方法可以在这里使用。正如其他人提到的,您可以在抽象类上创建以下构造函数参数:

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

case class Node(prop1: String, prop2: Int) extends Tree(prop1, prop2)
您还可以使它们成为常规VAL/VAR,并专门研究子类。这可以说是一个更好的解决方案,因为它使计算这些属性更容易,而不是通过构造函数简单地菊花链:

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
}

您也可以随意使用self类型,等等。如果我理解正确,您希望一些树节点具有具有该类型字段的类型。我想你要找的是一个。它们类似于泛型,但更适合分类。像这样的

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
}

这增加了间接性。但是我感觉你在一个步骤中概念化了一些东西,其中两个步骤是必要的。

你修改了Tree类。我想避免这种情况,因为它在许多地方都使用,而且我只需要在一个地方使用更丰富的树。@Łukasz-Lew:然后在继承结构中引入一个新层,用于捕获这种区别,并将共享元素放在该级别的一个(抽象)类中。