是否可以在案例类中实现双向树。这似乎应该很容易,但我很难过
case class Node(name:String, parent:Option[Node], children:List[Node])
我想添加一个孩子(并获得一个新的根) - 类似于
def addChild(n:String):Node = {
Node(name, parent, Node(n, Some(this), Nil)::children)
}
但这不起作用,因为孩子中的“父母”将不再引用将孩子列为孩子的节点。这是否可以使用不可变列表和案例类?
根据以下给出的答案
case class Node(name: String, parent: () => Option[Node], children: List[Node]) {
def makeChild(name: String) = {
lazy val newParent:Node = Node(this.name, this.parent, kid :: this.children)
lazy val kid:Node = Node(name, () => Some(newParent), Nil)
newParent
}
}
答案 0 :(得分:9)
我最近在Twitter上向@jamesiry提出了同样的问题: - )。
他的回答:
sealed abstract class Tree[T]
case class Node[T](left : Tree[T], right : Tree[T]) extends Tree[T]
case class Leaf[T](value : T, parent : () => Tree[T]) extends Tree[T]
def make = {
lazy val root = Node(left, right)
lazy val left : Leaf[Int] = Leaf(1, () => root)
lazy val right : Leaf[Int] = Leaf(2, () => root)
root
}
答案 1 :(得分:0)
请注意:想一下案例类是表示树的好选择。
由于case类是值类型,返回parent的唯一方法是返回父类的副本,包括完整子树的副本。然后,如果您举例说明其子项,您将再次获得完整子树的副本。
如果您想在树中进行一些替换,例如在更深层次上替换节点,唯一的方法是复制完整的树并丢弃旧树。
这一切看起来有点笨拙,但是例如lift-json使用case类来表示JSON AST,所以它可能不是那么大的问题。不确定Scala在复制时参考共享有多好。也许有人可以评论?
如果您确实想要使用案例类,那么上述延迟评估的答案是正确的。