我在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能够处理所有树木。
答案 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
}
您也应该随意使用自我类型等。