正如Scala文档所说,“案例类是按结构而不是按引用进行比较”。
我正在尝试创建一个带有循环的链表,然后将这个循环表中的节点添加到可变集合中。当使用常规类时,它成功了,但是在案例类中,我遇到了堆栈溢出。
我很好奇,为什么Scala在检查结构之前不first检查参考。我的想法是,如果引用相同,则可以保证结构相同,因此这可以是一种快捷方式,也可以使用循环引用。
代码:
object CaseClassHashcodeExample {
def main(args: Array[String]): Unit = {
val head = new ListNode(0)
head.appendToTail(1)
head.appendToTail(2)
head.appendToTail(3)
head.next.next.next = head.next
val set = collection.mutable.Set[ListNode]()
set.add(head)
assert(set(head))
}
}
case class ListNode(var data: Int, var next: ListNode = null) {
def appendToTail(d: Int): Unit = {
val end = new ListNode(d)
var cur = this
while (cur.next != null)
cur = cur.next
cur.next = end
}
}
我很好奇,为什么Scala在检查结构之前不先检查参考信息
嗯,您想要什么[[确切地检查?当前生成的代码看起来像
def hashCode() = 31 * data.hashCode() + next.hashCode()
您可以尝试的一件事是
def hashCode() = if (next != this) 31 * data.hashCode() + next.hashCode() else ???
但实际上并没有帮助:在您的情况下,不是next
等于this
,而是next.next
。
next.hashCode
不知道它是从this.hashCode
调用的,因此无法将其自己的next
与this
进行比较。您可以创建一个考虑一组“可见”对象的辅助方法:
def hashCode() = hashCode(Nil) def hashCode(seen: List[ListNode]) = if (seen.contains(this)) 0 else 31 * data.hashCode() + next.hashCode(this :: seen)
但是这两者都大大降低了普通情况的速度,并且很难正确解决。