在Scala中case类的值可以包含自身吗?

13z8s7eq  于 2023-10-18  发布在  Scala
关注(0)|答案(1)|浏览(151)

给定一棵树,其形状如下:

enum Tree
  case Node(left: Tree, right:Tree)
  case Leaf

是否可以创建一个值n:Node,使得n.left == n || n.right == nval n:Node = Node(n,n)不起作用,但是否有编译时保证不存在这样的值?对于一般的case类,是否有这样的保证(即a.a==a可能永远不适用于任何a:A,其中A是case类)?
一点额外的上下文:我遇到这个问题是因为我需要知道Tree s的集合是否形成一个单一的、格式良好的树,并且在某个时候想要检查所述集合是否有任何Node s引用它们自己。

bq3bfh9z

bq3bfh9z1#

有了class(case class也不例外),你就可以急切地计算作为参数传递给构造函数的每个表达式。lazydef不会有帮助,因为在一天结束时,您必须获得引用,并且在构造函数运行之前无法获得它。在构造函数内部,实际上是你第一次获得对(尚未完全构造的)对象的引用。
您必须使用var或运行时反射来设置此值:

final case class Data(var data: Data)

val data = locally {
  val recurData = Data(null.asInstanceOf[Data])
  recurData.data = recurData
  recurData
}

data.data == data

version with var

final case class Data(data: Data)

val data = locally {
  val recurData = Data(null.asInstanceOf[Data])
  val field = recurData.getClass.getDeclaredField("data")
  field.setAccessible(true)
  field.set(recurData, recurData)
  recurData
}

data.data == data

version with reflection
如果这不是一个case类,你可以在构造函数的主体中做一些奇怪的事情-如果你自己设置val,你可以使用一些逻辑来决定引用来自哪里,并将this作为引用would be accessible

class WeirdClass private (refE: Either[Unit, WeirdClass]) {
  def this() = this(Left(()))
  def this(ref: WeirdClass) = this(Right(ref))

  val ref: WeirdClass = refE.getOrElse(this)
}

val w = new WeirdClass()
w.ref == w

普通的case类,即使有辅助构造函数,不会让你对在构造函数参数列表中定义的val做这样的事情-构造函数参数列表中的值是用你传递给它的值初始化的,没有办法定制它。(甚至默认值也会在调用构造函数之前执行),辅助构造函数不允许您将this用作除了要调用的对象之外的任何对象(this(this)导致编译错误)。
因此,只要你使用的是普通的case类,让Scala生成val s定义,并确保没有人使用vars或反射,它就永远不会发生。

相关问题