3

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

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

现在我想向树中的所有节点和叶子添加一个成员变量。是否可以使用扩展关键字,或者我是否必须通过添加 [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

4 回答 4

2

如果我理解正确,您希望您的某些树节点具有具有该类型字段的类型。我认为您正在寻找抽象类型。它们就像泛型,但更适合子类化。像这样的东西。

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
}

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

于 2010-05-12T17:15:46.920 回答
0

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


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

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

于 2010-05-09T12:35:12.903 回答
0

抽象类可能有构造函数(特征可能没有),所以你可以把公共元素放在abstract class Tree

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

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

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

于 2010-05-09T14:42:52.743 回答
0

If the member(s) you're adding are valid for all Tree objects (and subclasses) then the logical place is to put them in the Tree object itself.

You have two techniques available two you here. As mentioned by others, you can make these constructor params on the abstract class:

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

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

You can also make them regular vals/vars and specialise in the subclasses. This is arguably a better solution as it makes it easier to calculate these properties instead of simply daisy-chaining them via constructors:

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
}

Using lazy vals here makes it easier to reason about the initialisation order of your object, it also avoids any computational overhead if the property is never used. This also shows nicely how methods in Scala can be implemented by properties, the so-called uniform access principle.

If you take this approach, then it's also possible to introduce the properties via a trait:

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
}

You should also feel free to use self-types, etc. as appropriate.

于 2010-05-11T07:38:28.737 回答