Scala 带有case类的双向引用

Scala 带有case类的双向引用,scala,case-class,Scala,Case Class,是否可以在案例类中实现双向树。这看起来应该很容易,但我被难倒了 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 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
  }
}

我最近在推特上向@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
}

请注意:请考虑案例类是否是表示树的好选项

由于case类是值类型,返回parent的唯一方法是返回父类的副本,包括完整子树的副本。例如,如果您枚举它的子树,您将再次获得完整子树的副本

如果要在树中执行某些替换,例如,在更深层次上替换节点,唯一的方法是复制完整树并丢弃旧树

这一切看起来有点笨拙,但例如,使用case类来表示JSON AST,所以这可能不是什么大问题。不确定复制时Scala在引用共享方面有多好。也许有人可以评论


如果您确实想使用案例类,上面的答案和惰性评估是正确的。

尝试对父类进行惰性评估。您真的应该将代码粘贴到答案中,而不是重定向到另一个站点。是的,很抱歉,这太草率了,因为我赶时间:-(。感谢缺少编辑答案的Faktor。